cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

imgui.cpp (507372B)


      1// dear imgui, v1.76
      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 for demo code. 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 I need 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
     33Index of this file:
     34
     35DOCUMENTATION
     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
     50CODE
     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 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/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.
    376 - 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.
    377 - 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.
    378 - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017):
    379                       - ShowTestWindow()                    -> use ShowDemoWindow()
    380                       - IsRootWindowFocused()               -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)
    381                       - IsRootWindowOrAnyChildFocused()     -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
    382                       - SetNextWindowContentWidth(w)        -> use SetNextWindowContentSize(ImVec2(w, 0.0f)
    383                       - GetItemsLineHeightWithSpacing()     -> use GetFrameHeightWithSpacing()
    384                       - ImGuiCol_ChildWindowBg              -> use ImGuiCol_ChildBg
    385                       - ImGuiStyleVar_ChildWindowRounding   -> use ImGuiStyleVar_ChildRounding
    386                       - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap
    387                       - IMGUI_DISABLE_TEST_WINDOWS          -> use IMGUI_DISABLE_DEMO_WINDOWS
    388 - 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.
    389 - 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).
    390 - 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.
    391 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
    392 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.
    393 - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017):
    394                       - Begin() [old 5 args version]        -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed
    395                       - IsRootWindowOrAnyChildHovered()     -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows)
    396                       - AlignFirstTextHeightToWidgets()     -> use AlignTextToFramePadding()
    397                       - SetNextWindowPosCenter()            -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f)
    398                       - ImFont::Glyph                       -> use ImFontGlyph
    399 - 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.
    400                       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.
    401                       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).
    402                       If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.
    403 - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
    404 - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
    405 - 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.
    406 - 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
    407                       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.
    408                       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.
    409                       Please reach out if you are affected.
    410 - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
    411 - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
    412 - 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.
    413 - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
    414 - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
    415 - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).
    416 - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with a dummy small value!
    417 - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
    418 - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
    419 - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
    420 - 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.
    421 - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
    422 - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
    423 - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
    424 - 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.
    425                       If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
    426 - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
    427 - 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.
    428                       NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.
    429                       Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.
    430 - 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).
    431 - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
    432 - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
    433 - 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.
    434 - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
    435 - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
    436 - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
    437 - 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.).
    438                       old bindings will still work as is, however prefer using the separated bindings as they will be updated to support multi-viewports.
    439                       when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call.
    440                       in particular, note that old bindings called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function.
    441 - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
    442 - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
    443 - 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.
    444                       If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
    445                       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.
    446                       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.
    447 - 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",
    448                       consistent with other functions. Kept redirection functions (will obsolete).
    449 - 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.
    450 - 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).
    451 - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
    452 - 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.
    453 - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
    454 - 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.
    455 - 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.
    456 - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
    457                       - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
    458                       - removed Shutdown() function, as DestroyContext() serve this purpose.
    459                       - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
    460                       - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
    461                       - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
    462 - 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.
    463 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
    464 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
    465 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
    466 - 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.
    467 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
    468 - 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
    469 - 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.
    470 - 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.
    471 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
    472 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
    473                     - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
    474 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
    475 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
    476 - 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.
    477 - 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.
    478                       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.
    479 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
    480 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
    481 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
    482 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
    483 - 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.
    484 - 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.
    485 - 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.
    486                       removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
    487                         IsItemHoveredRect()        --> IsItemHovered(ImGuiHoveredFlags_RectOnly)
    488                         IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
    489                         IsMouseHoveringWindow()    --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]
    490 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
    491 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
    492 - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).
    493 - 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).
    494 - 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)".
    495 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
    496                     - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
    497                     - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
    498 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
    499 - 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.
    500 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.
    501 - 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.
    502 - 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).
    503 - 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).
    504 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
    505 - 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.
    506                     - 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.
    507                     - 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))'
    508 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
    509 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
    510 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
    511 - 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().
    512 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
    513 - 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.
    514 - 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.
    515 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
    516                       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.
    517                       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:
    518                       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); }
    519                       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.
    520 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
    521 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
    522 - 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).
    523 - 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.
    524 - 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).
    525 - 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)
    526 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
    527 - 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.
    528 - 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.
    529 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
    530 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
    531 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
    532                       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.
    533                       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!
    534 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
    535 - 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.
    536 - 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
    537 - 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.
    538                       you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
    539 - 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.
    540                       this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
    541                     - 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.
    542                     - the signature of the io.RenderDrawListsFn handler has changed!
    543                       old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
    544                       new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
    545                         parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
    546                         ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
    547                         ImDrawCmd:  'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
    548                     - 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.
    549                     - 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!
    550                     - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
    551 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
    552 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
    553 - 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.
    554 - 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
    555 - 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!
    556 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
    557 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
    558 - 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.
    559 - 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.
    560 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
    561 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
    562 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
    563 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
    564 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
    565 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
    566 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
    567 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
    568 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
    569 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
    570 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
    571 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
    572 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
    573 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
    574 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
    575 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
    576 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
    577 - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
    578                       - old:  const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..];
    579                       - new:  unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->TexId = YourTexIdentifier;
    580                       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.
    581 - 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.
    582 - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
    583 - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
    584 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
    585 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
    586 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
    587 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
    588 - 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)
    589 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
    590 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
    591 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
    592 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
    593 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
    594 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
    595
    596
    597 FREQUENTLY ASKED QUESTIONS (FAQ)
    598 ================================
    599
    600 Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer)
    601 Some answers are copied down here to facilitate searching in code.
    602
    603 Q&A: Basics
    604 ===========
    605
    606 Q: Where is the documentation?
    607 A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
    608    - Run the examples/ and explore them.
    609    - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
    610    - The demo covers most features of Dear ImGui, so you can read the code and see its output.
    611    - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
    612    - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the
    613      examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
    614    - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.
    615    - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.
    616    - Your programming IDE is your friend, find the type or function declaration to find comments
    617      associated to it.
    618
    619 Q: What is this library called?
    620 Q: Which version should I get?
    621 >> This library is called "Dear ImGui", please don't call it "ImGui" :)
    622 >> See https://www.dearimgui.org/faq
    623
    624 Q&A: Integration
    625 ================
    626
    627 Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application?
    628 A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
    629 >> See https://www.dearimgui.org/faq for fully detailed answer. You really want to read this.
    630
    631 Q. How can I enable keyboard controls?
    632 Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
    633 Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
    634 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
    635 >> See https://www.dearimgui.org/faq
    636
    637 Q&A: Usage
    638 ----------
    639
    640 Q: Why are multiple widgets reacting when I interact with a single one?
    641 Q: How can I have multiple widgets with the same label or with an empty label?
    642 A: A primer on labels and the ID Stack...
    643
    644    Dear ImGui internally need to uniquely identify UI elements.
    645    Elements that are typically not clickable (such as calls to the Text functions) don't need an ID.
    646    Interactive widgets (such as calls to Button buttons) need a unique ID.
    647    Unique ID are used internally to track active widgets and occasionally associate state to widgets.
    648    Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element.
    649
    650   - Unique ID are often derived from a string label:
    651
    652       Button("OK");          // Label = "OK",     ID = hash of (..., "OK")
    653       Button("Cancel");      // Label = "Cancel", ID = hash of (..., "Cancel")
    654
    655   - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having
    656     two buttons labeled "OK" in different windows or different tree locations is fine.
    657     We used "..." above to signify whatever was already pushed to the ID stack previously:
    658
    659       Begin("MyWindow");
    660       Button("OK");          // Label = "OK",     ID = hash of ("MyWindow", "OK")
    661       End();
    662       Begin("MyOtherWindow");
    663       Button("OK");          // Label = "OK",     ID = hash of ("MyOtherWindow", "OK")
    664       End();
    665
    666   - If you have a same ID twice in the same location, you'll have a conflict:
    667
    668       Button("OK");
    669       Button("OK");          // ID collision! Interacting with either button will trigger the first one.
    670
    671     Fear not! this is easy to solve and there are many ways to solve it!
    672
    673   - Solving ID conflict in a simple/local context:
    674     When passing a label you can optionally specify extra ID information within string itself.
    675     Use "##" to pass a complement to the ID that won't be visible to the end-user.
    676     This helps solving the simple collision cases when you know e.g. at compilation time which items
    677     are going to be created:
    678
    679       Begin("MyWindow");
    680       Button("Play");        // Label = "Play",   ID = hash of ("MyWindow", "Play")
    681       Button("Play##foo1");  // Label = "Play",   ID = hash of ("MyWindow", "Play##foo1")  // Different from above
    682       Button("Play##foo2");  // Label = "Play",   ID = hash of ("MyWindow", "Play##foo2")  // Different from above
    683       End();
    684
    685   - If you want to completely hide the label, but still need an ID:
    686
    687       Checkbox("##On", &b);  // Label = "",       ID = hash of (..., "##On")   // No visible label, just a checkbox!
    688
    689   - Occasionally/rarely you might want change a label while preserving a constant ID. This allows
    690     you to animate labels. For example you may want to include varying information in a window title bar,
    691     but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID:
    692
    693       Button("Hello###ID");  // Label = "Hello",  ID = hash of (..., "###ID")
    694       Button("World###ID");  // Label = "World",  ID = hash of (..., "###ID")  // Same as above, even though the label looks different
    695
    696       sprintf(buf, "My game (%f FPS)###MyGame", fps);
    697       Begin(buf);            // Variable title,   ID = hash of "MyGame"
    698
    699   - Solving ID conflict in a more general manner:
    700     Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts
    701     within the same window. This is the most convenient way of distinguishing ID when iterating and
    702     creating many UI elements programmatically.
    703     You can push a pointer, a string or an integer value into the ID stack.
    704     Remember that ID are formed from the concatenation of _everything_ pushed into the ID stack.
    705     At each level of the stack we store the seed used for items at this level of the ID stack.
    706
    707     Begin("Window");
    708       for (int i = 0; i < 100; i++)
    709       {
    710         PushID(i);           // Push i to the id tack
    711         Button("Click");     // Label = "Click",  ID = hash of ("Window", i, "Click")
    712         PopID();
    713       }
    714       for (int i = 0; i < 100; i++)
    715       {
    716         MyObject* obj = Objects[i];
    717         PushID(obj);
    718         Button("Click");     // Label = "Click",  ID = hash of ("Window", obj pointer, "Click")
    719         PopID();
    720       }
    721       for (int i = 0; i < 100; i++)
    722       {
    723         MyObject* obj = Objects[i];
    724         PushID(obj->Name);
    725         Button("Click");     // Label = "Click",  ID = hash of ("Window", obj->Name, "Click")
    726         PopID();
    727       }
    728       End();
    729
    730   - You can stack multiple prefixes into the ID stack:
    731
    732       Button("Click");       // Label = "Click",  ID = hash of (..., "Click")
    733       PushID("node");
    734       Button("Click");       // Label = "Click",  ID = hash of (..., "node", "Click")
    735         PushID(my_ptr);
    736           Button("Click");   // Label = "Click",  ID = hash of (..., "node", my_ptr, "Click")
    737         PopID();
    738       PopID();
    739
    740   - Tree nodes implicitly creates a scope for you by calling PushID().
    741
    742       Button("Click");       // Label = "Click",  ID = hash of (..., "Click")
    743       if (TreeNode("node"))  // <-- this function call will do a PushID() for you (unless instructed not to, with a special flag)
    744       {
    745         Button("Click");     // Label = "Click",  ID = hash of (..., "node", "Click")
    746         TreePop();
    747       }
    748
    749   - When working with trees, ID are used to preserve the open/close state of each tree node.
    750     Depending on your use cases you may want to use strings, indices or pointers as ID.
    751      e.g. when following a single pointer that may change over time, using a static string as ID
    752       will preserve your node open/closed state when the targeted object change.
    753      e.g. when displaying a list of objects, using indices or pointers as ID will preserve the
    754       node open/closed state differently. See what makes more sense in your situation!
    755
    756 Q: How can I display an image? What is ImTextureID, how does it works?
    757 >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
    758
    759 Q: How can I use my own math types instead of ImVec2/ImVec4?
    760 Q: How can I interact with standard C++ types (such as std::string and std::vector)?
    761 Q: How can I display custom shapes? (using low-level ImDrawList API)
    762 >> See https://www.dearimgui.org/faq
    763
    764 Q&A: Fonts, Text
    765 ================
    766
    767 Q: How can I load a different font than the default?
    768 Q: How can I easily use icons in my application?
    769 Q: How can I load multiple fonts?
    770 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
    771 >> See https://www.dearimgui.org/faq and docs/FONTS.txt
    772
    773 Q&A: Concerns
    774 =============
    775
    776 Q: Who uses Dear ImGui?
    777 Q: Can you create elaborate/serious tools with Dear ImGui?
    778 Q: Can you reskin the look of Dear ImGui?
    779 Q: Why using C++ (as opposed to C)?
    780 >> See https://www.dearimgui.org/faq
    781
    782 Q&A: Community
    783 ==============
    784
    785 Q: How can I help?
    786 A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui!
    787      We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
    788      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.
    789    - Individuals: you can support continued development via PayPal donations. See README.
    790    - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt
    791      and see how you want to help and can help!
    792    - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
    793      You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/3075). Visuals are ideal as they inspire other programmers.
    794      But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
    795    - 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).
    796
    797*/
    798
    799//-------------------------------------------------------------------------
    800// [SECTION] INCLUDES
    801//-------------------------------------------------------------------------
    802
    803#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
    804#define _CRT_SECURE_NO_WARNINGS
    805#endif
    806
    807#include "imgui.h"
    808#ifndef IMGUI_DISABLE
    809
    810#ifndef IMGUI_DEFINE_MATH_OPERATORS
    811#define IMGUI_DEFINE_MATH_OPERATORS
    812#endif
    813#include "imgui_internal.h"
    814
    815// System includes
    816#include <ctype.h>      // toupper
    817#include <stdio.h>      // vsnprintf, sscanf, printf
    818#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
    819#include <stddef.h>     // intptr_t
    820#else
    821#include <stdint.h>     // intptr_t
    822#endif
    823
    824// [Windows] OS specific includes (optional)
    825#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)
    826#define IMGUI_DISABLE_WIN32_FUNCTIONS
    827#endif
    828#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
    829#ifndef WIN32_LEAN_AND_MEAN
    830#define WIN32_LEAN_AND_MEAN
    831#endif
    832#ifndef NOMINMAX
    833#define NOMINMAX
    834#endif
    835#ifndef __MINGW32__
    836#include <Windows.h>        // _wfopen, OpenClipboard
    837#else
    838#include <windows.h>
    839#endif
    840#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions
    841#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
    842#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
    843#endif
    844#endif
    845
    846// [Apple] OS specific includes
    847#if defined(__APPLE__)
    848#include <TargetConditionals.h>
    849#endif
    850
    851// Visual Studio warnings
    852#ifdef _MSC_VER
    853#pragma warning (disable: 4127)             // condition expression is constant
    854#pragma warning (disable: 4996)             // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
    855#if defined(_MSC_VER) && _MSC_VER >= 1922   // MSVC 2019 16.2 or later
    856#pragma warning (disable: 5054)             // operator '|': deprecated between enumerations of different types
    857#endif
    858#endif
    859
    860// Clang/GCC warnings with -Weverything
    861#if defined(__clang__)
    862#pragma clang diagnostic ignored "-Wunknown-pragmas"        // warning : unknown warning group '-Wformat-pedantic *'        // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great!
    863#pragma clang diagnostic ignored "-Wold-style-cast"         // warning : use of old-style cast                              // yes, they are more terse.
    864#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.
    865#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.
    866#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.
    867#pragma clang diagnostic ignored "-Wglobal-constructors"    // warning : declaration requires a global destructor           // similar to above, not sure what the exact difference is.
    868#pragma clang diagnostic ignored "-Wsign-conversion"        // warning : implicit conversion changes signedness             //
    869#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.
    870#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning : cast to 'void *' from smaller integer type 'int'
    871#if __has_warning("-Wzero-as-null-pointer-constant")
    872#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning : zero as null pointer constant              // some standard header variations use #define NULL 0
    873#endif
    874#if __has_warning("-Wdouble-promotion")
    875#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.
    876#endif
    877#elif defined(__GNUC__)
    878// We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association.
    879#pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
    880#pragma GCC diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
    881#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"      // warning: cast to pointer from integer of different size
    882#pragma GCC diagnostic ignored "-Wformat"                   // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
    883#pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
    884#pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
    885#pragma GCC diagnostic ignored "-Wformat-nonliteral"        // warning: format not a string literal, format string not checked
    886#pragma GCC diagnostic ignored "-Wstrict-overflow"          // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
    887#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
    888#endif
    889
    890// Debug options
    891#define IMGUI_DEBUG_NAV_SCORING     0   // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL
    892#define IMGUI_DEBUG_NAV_RECTS       0   // Display the reference navigation rectangle for each window
    893#define IMGUI_DEBUG_INI_SETTINGS    0   // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower)
    894
    895// 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.
    896static const float NAV_WINDOWING_HIGHLIGHT_DELAY            = 0.20f;    // Time before the highlight and screen dimming starts fading in
    897static const float NAV_WINDOWING_LIST_APPEAR_DELAY          = 0.15f;    // Time before the window list starts to appear
    898
    899// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end)
    900static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f;     // Extend outside and inside windows. Affect FindHoveredWindow().
    901static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f;    // Reduce visual noise by only highlighting the border after a certain time.
    902static 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 certaint time, unless mouse moved.
    903
    904//-------------------------------------------------------------------------
    905// [SECTION] FORWARD DECLARATIONS
    906//-------------------------------------------------------------------------
    907
    908static void             SetCurrentWindow(ImGuiWindow* window);
    909static void             FindHoveredWindow();
    910static ImGuiWindow*     CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags);
    911static ImVec2           CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges);
    912
    913static void             AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
    914static void             AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
    915
    916static ImRect           GetViewportRect();
    917
    918// Settings
    919static void*            WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
    920static void             WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
    921static void             WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
    922
    923// Platform Dependents default implementation for IO functions
    924static const char*      GetClipboardTextFn_DefaultImpl(void* user_data);
    925static void             SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
    926static void             ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
    927
    928namespace ImGui
    929{
    930// Navigation
    931static void             NavUpdate();
    932static void             NavUpdateWindowing();
    933static void             NavUpdateWindowingOverlay();
    934static void             NavUpdateMoveResult();
    935static float            NavUpdatePageUpPageDown();
    936static inline void      NavUpdateAnyRequestFlag();
    937static bool             NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
    938static void             NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
    939static ImVec2           NavCalcPreferredRefPos();
    940static void             NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
    941static ImGuiWindow*     NavRestoreLastChildNavWindow(ImGuiWindow* window);
    942static int              FindWindowFocusIndex(ImGuiWindow* window);
    943
    944// Error Checking
    945static void             ErrorCheckNewFrameSanityChecks();
    946static void             ErrorCheckEndFrameSanityChecks();
    947static void             ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write);
    948
    949// Misc
    950static void             UpdateSettings();
    951static void             UpdateMouseInputs();
    952static void             UpdateMouseWheel();
    953static void             UpdateTabFocus();
    954static void             UpdateDebugToolItemPicker();
    955static bool             UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
    956static void             RenderWindowOuterBorders(ImGuiWindow* window);
    957static 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);
    958static void             RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
    959
    960}
    961
    962//-----------------------------------------------------------------------------
    963// [SECTION] CONTEXT AND MEMORY ALLOCATORS
    964//-----------------------------------------------------------------------------
    965
    966// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
    967// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
    968// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call
    969//    SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading.
    970//    In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into.
    971// 2) Important: Dear ImGui functions are not thread-safe because of this pointer.
    972//    If you want thread-safety to allow N threads to access N different contexts, you can:
    973//    - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h:
    974//          struct ImGuiContext;
    975//          extern thread_local ImGuiContext* MyImGuiTLS;
    976//          #define GImGui MyImGuiTLS
    977//      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.
    978//    - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
    979//    - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace.
    980#ifndef GImGui
    981ImGuiContext*   GImGui = NULL;
    982#endif
    983
    984// Memory Allocator functions. Use SetAllocatorFunctions() to change them.
    985// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file.
    986// 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.
    987#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
    988static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); return malloc(size); }
    989static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); free(ptr); }
    990#else
    991static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
    992static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
    993#endif
    994
    995static void*  (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
    996static void   (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
    997static void*    GImAllocatorUserData = NULL;
    998
    999//-----------------------------------------------------------------------------
   1000// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
   1001//-----------------------------------------------------------------------------
   1002
   1003ImGuiStyle::ImGuiStyle()
   1004{
   1005    Alpha                   = 1.0f;             // Global alpha applies to everything in ImGui
   1006    WindowPadding           = ImVec2(8,8);      // Padding within a window
   1007    WindowRounding          = 7.0f;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows
   1008    WindowBorderSize        = 1.0f;             // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
   1009    WindowMinSize           = ImVec2(32,32);    // Minimum window size
   1010    WindowTitleAlign        = ImVec2(0.0f,0.5f);// Alignment for title bar text
   1011    WindowMenuButtonPosition= ImGuiDir_Left;    // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
   1012    ChildRounding           = 0.0f;             // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
   1013    ChildBorderSize         = 1.0f;             // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
   1014    PopupRounding           = 0.0f;             // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
   1015    PopupBorderSize         = 1.0f;             // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
   1016    FramePadding            = ImVec2(4,3);      // Padding within a framed rectangle (used by most widgets)
   1017    FrameRounding           = 0.0f;             // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
   1018    FrameBorderSize         = 0.0f;             // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
   1019    ItemSpacing             = ImVec2(8,4);      // Horizontal and vertical spacing between widgets/lines
   1020    ItemInnerSpacing        = ImVec2(4,4);      // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
   1021    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!
   1022    IndentSpacing           = 21.0f;            // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
   1023    ColumnsMinSpacing       = 6.0f;             // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
   1024    ScrollbarSize           = 14.0f;            // Width of the vertical scrollbar, Height of the horizontal scrollbar
   1025    ScrollbarRounding       = 9.0f;             // Radius of grab corners rounding for scrollbar
   1026    GrabMinSize             = 10.0f;            // Minimum width/height of a grab box for slider/scrollbar
   1027    GrabRounding            = 0.0f;             // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
   1028    TabRounding             = 4.0f;             // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
   1029    TabBorderSize           = 0.0f;             // Thickness of border around tabs.
   1030    ColorButtonPosition     = ImGuiDir_Right;   // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
   1031    ButtonTextAlign         = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
   1032    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.
   1033    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.
   1034    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.
   1035    MouseCursorScale        = 1.0f;             // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
   1036    AntiAliasedLines        = true;             // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
   1037    AntiAliasedFill         = true;             // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
   1038    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.
   1039    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.
   1040
   1041    // Default theme
   1042    ImGui::StyleColorsDark(this);
   1043}
   1044
   1045// 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.
   1046// 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.
   1047void ImGuiStyle::ScaleAllSizes(float scale_factor)
   1048{
   1049    WindowPadding = ImFloor(WindowPadding * scale_factor);
   1050    WindowRounding = ImFloor(WindowRounding * scale_factor);
   1051    WindowMinSize = ImFloor(WindowMinSize * scale_factor);
   1052    ChildRounding = ImFloor(ChildRounding * scale_factor);
   1053    PopupRounding = ImFloor(PopupRounding * scale_factor);
   1054    FramePadding = ImFloor(FramePadding * scale_factor);
   1055    FrameRounding = ImFloor(FrameRounding * scale_factor);
   1056    ItemSpacing = ImFloor(ItemSpacing * scale_factor);
   1057    ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
   1058    TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
   1059    IndentSpacing = ImFloor(IndentSpacing * scale_factor);
   1060    ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
   1061    ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
   1062    ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
   1063    GrabMinSize = ImFloor(GrabMinSize * scale_factor);
   1064    GrabRounding = ImFloor(GrabRounding * scale_factor);
   1065    TabRounding = ImFloor(TabRounding * scale_factor);
   1066    DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
   1067    DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
   1068    MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
   1069}
   1070
   1071ImGuiIO::ImGuiIO()
   1072{
   1073    // Most fields are initialized with zero
   1074    memset(this, 0, sizeof(*this));
   1075    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.
   1076
   1077    // Settings
   1078    ConfigFlags = ImGuiConfigFlags_None;
   1079    BackendFlags = ImGuiBackendFlags_None;
   1080    DisplaySize = ImVec2(-1.0f, -1.0f);
   1081    DeltaTime = 1.0f/60.0f;
   1082    IniSavingRate = 5.0f;
   1083    IniFilename = "imgui.ini";
   1084    LogFilename = "imgui_log.txt";
   1085    MouseDoubleClickTime = 0.30f;
   1086    MouseDoubleClickMaxDist = 6.0f;
   1087    for (int i = 0; i < ImGuiKey_COUNT; i++)
   1088        KeyMap[i] = -1;
   1089    KeyRepeatDelay = 0.275f;
   1090    KeyRepeatRate = 0.050f;
   1091    UserData = NULL;
   1092
   1093    Fonts = NULL;
   1094    FontGlobalScale = 1.0f;
   1095    FontDefault = NULL;
   1096    FontAllowUserScaling = false;
   1097    DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
   1098
   1099    // Miscellaneous options
   1100    MouseDrawCursor = false;
   1101#ifdef __APPLE__
   1102    ConfigMacOSXBehaviors = true;  // Set Mac OS X style defaults based on __APPLE__ compile time flag
   1103#else
   1104    ConfigMacOSXBehaviors = false;
   1105#endif
   1106    ConfigInputTextCursorBlink = true;
   1107    ConfigWindowsResizeFromEdges = true;
   1108    ConfigWindowsMoveFromTitleBarOnly = false;
   1109    ConfigWindowsMemoryCompactTimer = 60.0f;
   1110
   1111    // Platform Functions
   1112    BackendPlatformName = BackendRendererName = NULL;
   1113    BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
   1114    GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;   // Platform dependent default implementations
   1115    SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
   1116    ClipboardUserData = NULL;
   1117    ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
   1118    ImeWindowHandle = NULL;
   1119
   1120#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
   1121    RenderDrawListsFn = NULL;
   1122#endif
   1123
   1124    // Input (NB: we already have memset zero the entire structure!)
   1125    MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
   1126    MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
   1127    MouseDragThreshold = 6.0f;
   1128    for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
   1129    for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i]  = KeysDownDurationPrev[i] = -1.0f;
   1130    for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
   1131}
   1132
   1133// Pass in translated ASCII characters for text input.
   1134// - with glfw you can get those from the callback set in glfwSetCharCallback()
   1135// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
   1136void ImGuiIO::AddInputCharacter(unsigned int c)
   1137{
   1138    InputQueueCharacters.push_back(c > 0 && c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
   1139}
   1140
   1141// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
   1142// we should save the high surrogate.
   1143void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
   1144{
   1145    if ((c & 0xFC00) == 0xD800) // High surrogate, must save
   1146    {
   1147        if (InputQueueSurrogate != 0)
   1148            InputQueueCharacters.push_back(0xFFFD);
   1149        InputQueueSurrogate = c;
   1150        return;
   1151    }
   1152
   1153    ImWchar cp = c;
   1154    if (InputQueueSurrogate != 0)
   1155    {
   1156        if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
   1157            InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
   1158        else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) // Codepoint will not fit in ImWchar (extra parenthesis around 0xFFFF somehow fixes -Wunreachable-code with Clang)
   1159            cp = IM_UNICODE_CODEPOINT_INVALID;
   1160        else
   1161            cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
   1162        InputQueueSurrogate = 0;
   1163    }
   1164    InputQueueCharacters.push_back(cp);
   1165}
   1166
   1167void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
   1168{
   1169    while (*utf8_chars != 0)
   1170    {
   1171        unsigned int c = 0;
   1172        utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
   1173        if (c > 0)
   1174            InputQueueCharacters.push_back((ImWchar)c);
   1175    }
   1176}
   1177
   1178void ImGuiIO::ClearInputCharacters()
   1179{
   1180    InputQueueCharacters.resize(0);
   1181}
   1182
   1183//-----------------------------------------------------------------------------
   1184// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
   1185//-----------------------------------------------------------------------------
   1186
   1187ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
   1188{
   1189    IM_ASSERT(num_segments > 0); // Use ImBezierClosestPointCasteljau()
   1190    ImVec2 p_last = p1;
   1191    ImVec2 p_closest;
   1192    float p_closest_dist2 = FLT_MAX;
   1193    float t_step = 1.0f / (float)num_segments;
   1194    for (int i_step = 1; i_step <= num_segments; i_step++)
   1195    {
   1196        ImVec2 p_current = ImBezierCalc(p1, p2, p3, p4, t_step * i_step);
   1197        ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
   1198        float dist2 = ImLengthSqr(p - p_line);
   1199        if (dist2 < p_closest_dist2)
   1200        {
   1201            p_closest = p_line;
   1202            p_closest_dist2 = dist2;
   1203        }
   1204        p_last = p_current;
   1205    }
   1206    return p_closest;
   1207}
   1208
   1209// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp
   1210static 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)
   1211{
   1212    float dx = x4 - x1;
   1213    float dy = y4 - y1;
   1214    float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
   1215    float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
   1216    d2 = (d2 >= 0) ? d2 : -d2;
   1217    d3 = (d3 >= 0) ? d3 : -d3;
   1218    if ((d2+d3) * (d2+d3) < tess_tol * (dx*dx + dy*dy))
   1219    {
   1220        ImVec2 p_current(x4, y4);
   1221        ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
   1222        float dist2 = ImLengthSqr(p - p_line);
   1223        if (dist2 < p_closest_dist2)
   1224        {
   1225            p_closest = p_line;
   1226            p_closest_dist2 = dist2;
   1227        }
   1228        p_last = p_current;
   1229    }
   1230    else if (level < 10)
   1231    {
   1232        float x12 = (x1+x2)*0.5f,       y12 = (y1+y2)*0.5f;
   1233        float x23 = (x2+x3)*0.5f,       y23 = (y2+y3)*0.5f;
   1234        float x34 = (x3+x4)*0.5f,       y34 = (y3+y4)*0.5f;
   1235        float x123 = (x12+x23)*0.5f,    y123 = (y12+y23)*0.5f;
   1236        float x234 = (x23+x34)*0.5f,    y234 = (y23+y34)*0.5f;
   1237        float x1234 = (x123+x234)*0.5f, y1234 = (y123+y234)*0.5f;
   1238        BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
   1239        BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
   1240    }
   1241}
   1242
   1243// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol
   1244// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.
   1245ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
   1246{
   1247    IM_ASSERT(tess_tol > 0.0f);
   1248    ImVec2 p_last = p1;
   1249    ImVec2 p_closest;
   1250    float p_closest_dist2 = FLT_MAX;
   1251    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);
   1252    return p_closest;
   1253}
   1254
   1255ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
   1256{
   1257    ImVec2 ap = p - a;
   1258    ImVec2 ab_dir = b - a;
   1259    float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
   1260    if (dot < 0.0f)
   1261        return a;
   1262    float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
   1263    if (dot > ab_len_sqr)
   1264        return b;
   1265    return a + ab_dir * dot / ab_len_sqr;
   1266}
   1267
   1268bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
   1269{
   1270    bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
   1271    bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
   1272    bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
   1273    return ((b1 == b2) && (b2 == b3));
   1274}
   1275
   1276void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
   1277{
   1278    ImVec2 v0 = b - a;
   1279    ImVec2 v1 = c - a;
   1280    ImVec2 v2 = p - a;
   1281    const float denom = v0.x * v1.y - v1.x * v0.y;
   1282    out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
   1283    out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
   1284    out_u = 1.0f - out_v - out_w;
   1285}
   1286
   1287ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
   1288{
   1289    ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
   1290    ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
   1291    ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
   1292    float dist2_ab = ImLengthSqr(p - proj_ab);
   1293    float dist2_bc = ImLengthSqr(p - proj_bc);
   1294    float dist2_ca = ImLengthSqr(p - proj_ca);
   1295    float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
   1296    if (m == dist2_ab)
   1297        return proj_ab;
   1298    if (m == dist2_bc)
   1299        return proj_bc;
   1300    return proj_ca;
   1301}
   1302
   1303//-----------------------------------------------------------------------------
   1304// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
   1305//-----------------------------------------------------------------------------
   1306
   1307// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
   1308int ImStricmp(const char* str1, const char* str2)
   1309{
   1310    int d;
   1311    while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
   1312    return d;
   1313}
   1314
   1315int ImStrnicmp(const char* str1, const char* str2, size_t count)
   1316{
   1317    int d = 0;
   1318    while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
   1319    return d;
   1320}
   1321
   1322void ImStrncpy(char* dst, const char* src, size_t count)
   1323{
   1324    if (count < 1)
   1325        return;
   1326    if (count > 1)
   1327        strncpy(dst, src, count - 1);
   1328    dst[count - 1] = 0;
   1329}
   1330
   1331char* ImStrdup(const char* str)
   1332{
   1333    size_t len = strlen(str);
   1334    void* buf = IM_ALLOC(len + 1);
   1335    return (char*)memcpy(buf, (const void*)str, len + 1);
   1336}
   1337
   1338char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
   1339{
   1340    size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
   1341    size_t src_size = strlen(src) + 1;
   1342    if (dst_buf_size < src_size)
   1343    {
   1344        IM_FREE(dst);
   1345        dst = (char*)IM_ALLOC(src_size);
   1346        if (p_dst_size)
   1347            *p_dst_size = src_size;
   1348    }
   1349    return (char*)memcpy(dst, (const void*)src, src_size);
   1350}
   1351
   1352const char* ImStrchrRange(const char* str, const char* str_end, char c)
   1353{
   1354    const char* p = (const char*)memchr(str, (int)c, str_end - str);
   1355    return p;
   1356}
   1357
   1358int ImStrlenW(const ImWchar* str)
   1359{
   1360    //return (int)wcslen((const wchar_t*)str);  // FIXME-OPT: Could use this when wchar_t are 16-bit
   1361    int n = 0;
   1362    while (*str++) n++;
   1363    return n;
   1364}
   1365
   1366// Find end-of-line. Return pointer will point to either first \n, either str_end.
   1367const char* ImStreolRange(const char* str, const char* str_end)
   1368{
   1369    const char* p = (const char*)memchr(str, '\n', str_end - str);
   1370    return p ? p : str_end;
   1371}
   1372
   1373const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
   1374{
   1375    while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
   1376        buf_mid_line--;
   1377    return buf_mid_line;
   1378}
   1379
   1380const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
   1381{
   1382    if (!needle_end)
   1383        needle_end = needle + strlen(needle);
   1384
   1385    const char un0 = (char)toupper(*needle);
   1386    while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
   1387    {
   1388        if (toupper(*haystack) == un0)
   1389        {
   1390            const char* b = needle + 1;
   1391            for (const char* a = haystack + 1; b < needle_end; a++, b++)
   1392                if (toupper(*a) != toupper(*b))
   1393                    break;
   1394            if (b == needle_end)
   1395                return haystack;
   1396        }
   1397        haystack++;
   1398    }
   1399    return NULL;
   1400}
   1401
   1402// 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.
   1403void ImStrTrimBlanks(char* buf)
   1404{
   1405    char* p = buf;
   1406    while (p[0] == ' ' || p[0] == '\t')     // Leading blanks
   1407        p++;
   1408    char* p_start = p;
   1409    while (*p != 0)                         // Find end of string
   1410        p++;
   1411    while (p > p_start && (p[-1] == ' ' || p[-1] == '\t'))  // Trailing blanks
   1412        p--;
   1413    if (p_start != buf)                     // Copy memory if we had leading blanks
   1414        memmove(buf, p_start, p - p_start);
   1415    buf[p - p_start] = 0;                   // Zero terminate
   1416}
   1417
   1418const char* ImStrSkipBlank(const char* str)
   1419{
   1420    while (str[0] == ' ' || str[0] == '\t')
   1421        str++;
   1422    return str;
   1423}
   1424
   1425// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
   1426// 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.
   1427// B) When buf==NULL vsnprintf() will return the output size.
   1428#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
   1429
   1430// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)
   1431// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
   1432// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are
   1433// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
   1434#ifdef IMGUI_USE_STB_SPRINTF
   1435#define STB_SPRINTF_IMPLEMENTATION
   1436#include "stb_sprintf.h"
   1437#endif
   1438
   1439#if defined(_MSC_VER) && !defined(vsnprintf)
   1440#define vsnprintf _vsnprintf
   1441#endif
   1442
   1443int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
   1444{
   1445    va_list args;
   1446    va_start(args, fmt);
   1447#ifdef IMGUI_USE_STB_SPRINTF
   1448    int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
   1449#else
   1450    int w = vsnprintf(buf, buf_size, fmt, args);
   1451#endif
   1452    va_end(args);
   1453    if (buf == NULL)
   1454        return w;
   1455    if (w == -1 || w >= (int)buf_size)
   1456        w = (int)buf_size - 1;
   1457    buf[w] = 0;
   1458    return w;
   1459}
   1460
   1461int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
   1462{
   1463#ifdef IMGUI_USE_STB_SPRINTF
   1464    int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
   1465#else
   1466    int w = vsnprintf(buf, buf_size, fmt, args);
   1467#endif
   1468    if (buf == NULL)
   1469        return w;
   1470    if (w == -1 || w >= (int)buf_size)
   1471        w = (int)buf_size - 1;
   1472    buf[w] = 0;
   1473    return w;
   1474}
   1475#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
   1476
   1477// CRC32 needs a 1KB lookup table (not cache friendly)
   1478// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
   1479// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
   1480static const ImU32 GCrc32LookupTable[256] =
   1481{
   1482    0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
   1483    0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
   1484    0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
   1485    0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
   1486    0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
   1487    0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
   1488    0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
   1489    0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
   1490    0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
   1491    0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
   1492    0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
   1493    0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
   1494    0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
   1495    0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
   1496    0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
   1497    0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
   1498};
   1499
   1500// Known size hash
   1501// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
   1502// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
   1503ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed)
   1504{
   1505    ImU32 crc = ~seed;
   1506    const unsigned char* data = (const unsigned char*)data_p;
   1507    const ImU32* crc32_lut = GCrc32LookupTable;
   1508    while (data_size-- != 0)
   1509        crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
   1510    return ~crc;
   1511}
   1512
   1513// Zero-terminated string hash, with support for ### to reset back to seed value
   1514// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
   1515// Because this syntax is rarely used we are optimizing for the common case.
   1516// - If we reach ### in the string we discard the hash so far and reset to the seed.
   1517// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
   1518// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
   1519ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed)
   1520{
   1521    seed = ~seed;
   1522    ImU32 crc = seed;
   1523    const unsigned char* data = (const unsigned char*)data_p;
   1524    const ImU32* crc32_lut = GCrc32LookupTable;
   1525    if (data_size != 0)
   1526    {
   1527        while (data_size-- != 0)
   1528        {
   1529            unsigned char c = *data++;
   1530            if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
   1531                crc = seed;
   1532            crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
   1533        }
   1534    }
   1535    else
   1536    {
   1537        while (unsigned char c = *data++)
   1538        {
   1539            if (c == '#' && data[0] == '#' && data[1] == '#')
   1540                crc = seed;
   1541            crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
   1542        }
   1543    }
   1544    return ~crc;
   1545}
   1546
   1547//-----------------------------------------------------------------------------
   1548// [SECTION] MISC HELPERS/UTILITIES (File functions)
   1549//-----------------------------------------------------------------------------
   1550
   1551// Default file functions
   1552#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
   1553
   1554ImFileHandle ImFileOpen(const char* filename, const char* mode)
   1555{
   1556#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
   1557    // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
   1558    // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
   1559    const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
   1560    const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
   1561    ImVector<ImWchar> buf;
   1562    buf.resize(filename_wsize + mode_wsize);
   1563    ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
   1564    ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
   1565    return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]);
   1566#else
   1567    return fopen(filename, mode);
   1568#endif
   1569}
   1570
   1571// 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.
   1572bool    ImFileClose(ImFileHandle f)     { return fclose(f) == 0; }
   1573ImU64   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; }
   1574ImU64   ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f)           { return fread(data, (size_t)sz, (size_t)count, f); }
   1575ImU64   ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f)    { return fwrite(data, (size_t)sz, (size_t)count, f); }
   1576#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
   1577
   1578// Helper: Load file content into memory
   1579// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
   1580// This can't really be used with "rt" because fseek size won't match read size.
   1581void*   ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
   1582{
   1583    IM_ASSERT(filename && mode);
   1584    if (out_file_size)
   1585        *out_file_size = 0;
   1586
   1587    ImFileHandle f;
   1588    if ((f = ImFileOpen(filename, mode)) == NULL)
   1589        return NULL;
   1590
   1591    size_t file_size = (size_t)ImFileGetSize(f);
   1592    if (file_size == (size_t)-1)
   1593    {
   1594        ImFileClose(f);
   1595        return NULL;
   1596    }
   1597
   1598    void* file_data = IM_ALLOC(file_size + padding_bytes);
   1599    if (file_data == NULL)
   1600    {
   1601        ImFileClose(f);
   1602        return NULL;
   1603    }
   1604    if (ImFileRead(file_data, 1, file_size, f) != file_size)
   1605    {
   1606        ImFileClose(f);
   1607        IM_FREE(file_data);
   1608        return NULL;
   1609    }
   1610    if (padding_bytes > 0)
   1611        memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
   1612
   1613    ImFileClose(f);
   1614    if (out_file_size)
   1615        *out_file_size = file_size;
   1616
   1617    return file_data;
   1618}
   1619
   1620//-----------------------------------------------------------------------------
   1621// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
   1622//-----------------------------------------------------------------------------
   1623
   1624// Convert UTF-8 to 32-bit character, process single character input.
   1625// Based on stb_from_utf8() from github.com/nothings/stb/
   1626// We handle UTF-8 decoding error by skipping forward.
   1627int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
   1628{
   1629    unsigned int c = (unsigned int)-1;
   1630    const unsigned char* str = (const unsigned char*)in_text;
   1631    if (!(*str & 0x80))
   1632    {
   1633        c = (unsigned int)(*str++);
   1634        *out_char = c;
   1635        return 1;
   1636    }
   1637    if ((*str & 0xe0) == 0xc0)
   1638    {
   1639        *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
   1640        if (in_text_end && in_text_end - (const char*)str < 2) return 1;
   1641        if (*str < 0xc2) return 2;
   1642        c = (unsigned int)((*str++ & 0x1f) << 6);
   1643        if ((*str & 0xc0) != 0x80) return 2;
   1644        c += (*str++ & 0x3f);
   1645        *out_char = c;
   1646        return 2;
   1647    }
   1648    if ((*str & 0xf0) == 0xe0)
   1649    {
   1650        *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
   1651        if (in_text_end && in_text_end - (const char*)str < 3) return 1;
   1652        if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
   1653        if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
   1654        c = (unsigned int)((*str++ & 0x0f) << 12);
   1655        if ((*str & 0xc0) != 0x80) return 3;
   1656        c += (unsigned int)((*str++ & 0x3f) << 6);
   1657        if ((*str & 0xc0) != 0x80) return 3;
   1658        c += (*str++ & 0x3f);
   1659        *out_char = c;
   1660        return 3;
   1661    }
   1662    if ((*str & 0xf8) == 0xf0)
   1663    {
   1664        *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
   1665        if (in_text_end && in_text_end - (const char*)str < 4) return 1;
   1666        if (*str > 0xf4) return 4;
   1667        if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
   1668        if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
   1669        c = (unsigned int)((*str++ & 0x07) << 18);
   1670        if ((*str & 0xc0) != 0x80) return 4;
   1671        c += (unsigned int)((*str++ & 0x3f) << 12);
   1672        if ((*str & 0xc0) != 0x80) return 4;
   1673        c += (unsigned int)((*str++ & 0x3f) << 6);
   1674        if ((*str & 0xc0) != 0x80) return 4;
   1675        c += (*str++ & 0x3f);
   1676        // utf-8 encodings of values used in surrogate pairs are invalid
   1677        if ((c & 0xFFFFF800) == 0xD800) return 4;
   1678        // If codepoint does not fit in ImWchar, use replacement character U+FFFD instead
   1679        if (c > IM_UNICODE_CODEPOINT_MAX) c = IM_UNICODE_CODEPOINT_INVALID;
   1680        *out_char = c;
   1681        return 4;
   1682    }
   1683    *out_char = 0;
   1684    return 0;
   1685}
   1686
   1687int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
   1688{
   1689    ImWchar* buf_out = buf;
   1690    ImWchar* buf_end = buf + buf_size;
   1691    while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
   1692    {
   1693        unsigned int c;
   1694        in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
   1695        if (c == 0)
   1696            break;
   1697        *buf_out++ = (ImWchar)c;
   1698    }
   1699    *buf_out = 0;
   1700    if (in_text_remaining)
   1701        *in_text_remaining = in_text;
   1702    return (int)(buf_out - buf);
   1703}
   1704
   1705int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
   1706{
   1707    int char_count = 0;
   1708    while ((!in_text_end || in_text < in_text_end) && *in_text)
   1709    {
   1710        unsigned int c;
   1711        in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
   1712        if (c == 0)
   1713            break;
   1714        char_count++;
   1715    }
   1716    return char_count;
   1717}
   1718
   1719// Based on stb_to_utf8() from github.com/nothings/stb/
   1720static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
   1721{
   1722    if (c < 0x80)
   1723    {
   1724        buf[0] = (char)c;
   1725        return 1;
   1726    }
   1727    if (c < 0x800)
   1728    {
   1729        if (buf_size < 2) return 0;
   1730        buf[0] = (char)(0xc0 + (c >> 6));
   1731        buf[1] = (char)(0x80 + (c & 0x3f));
   1732        return 2;
   1733    }
   1734    if (c < 0x10000)
   1735    {
   1736        if (buf_size < 3) return 0;
   1737        buf[0] = (char)(0xe0 + (c >> 12));
   1738        buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
   1739        buf[2] = (char)(0x80 + ((c ) & 0x3f));
   1740        return 3;
   1741    }
   1742    if (c <= 0x10FFFF)
   1743    {
   1744        if (buf_size < 4) return 0;
   1745        buf[0] = (char)(0xf0 + (c >> 18));
   1746        buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
   1747        buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
   1748        buf[3] = (char)(0x80 + ((c ) & 0x3f));
   1749        return 4;
   1750    }
   1751    // Invalid code point, the max unicode is 0x10FFFF
   1752    return 0;
   1753}
   1754
   1755// Not optimal but we very rarely use this function.
   1756int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
   1757{
   1758    unsigned int dummy = 0;
   1759    return ImTextCharFromUtf8(&dummy, in_text, in_text_end);
   1760}
   1761
   1762static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
   1763{
   1764    if (c < 0x80) return 1;
   1765    if (c < 0x800) return 2;
   1766    if (c < 0x10000) return 3;
   1767    if (c <= 0x10FFFF) return 4;
   1768    return 3;
   1769}
   1770
   1771int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
   1772{
   1773    char* buf_out = buf;
   1774    const char* buf_end = buf + buf_size;
   1775    while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
   1776    {
   1777        unsigned int c = (unsigned int)(*in_text++);
   1778        if (c < 0x80)
   1779            *buf_out++ = (char)c;
   1780        else
   1781            buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c);
   1782    }
   1783    *buf_out = 0;
   1784    return (int)(buf_out - buf);
   1785}
   1786
   1787int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
   1788{
   1789    int bytes_count = 0;
   1790    while ((!in_text_end || in_text < in_text_end) && *in_text)
   1791    {
   1792        unsigned int c = (unsigned int)(*in_text++);
   1793        if (c < 0x80)
   1794            bytes_count++;
   1795        else
   1796            bytes_count += ImTextCountUtf8BytesFromChar(c);
   1797    }
   1798    return bytes_count;
   1799}
   1800
   1801//-----------------------------------------------------------------------------
   1802// [SECTION] MISC HELPERS/UTILITIES (Color functions)
   1803// Note: The Convert functions are early design which are not consistent with other API.
   1804//-----------------------------------------------------------------------------
   1805
   1806IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)
   1807{
   1808    float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
   1809    int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
   1810    int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
   1811    int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
   1812    return IM_COL32(r, g, b, 0xFF);
   1813}
   1814
   1815ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
   1816{
   1817    float s = 1.0f/255.0f;
   1818    return ImVec4(
   1819        ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
   1820        ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
   1821        ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
   1822        ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
   1823}
   1824
   1825ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
   1826{
   1827    ImU32 out;
   1828    out  = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
   1829    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
   1830    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
   1831    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
   1832    return out;
   1833}
   1834
   1835// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
   1836// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
   1837void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
   1838{
   1839    float K = 0.f;
   1840    if (g < b)
   1841    {
   1842        ImSwap(g, b);
   1843        K = -1.f;
   1844    }
   1845    if (r < g)
   1846    {
   1847        ImSwap(r, g);
   1848        K = -2.f / 6.f - K;
   1849    }
   1850
   1851    const float chroma = r - (g < b ? g : b);
   1852    out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
   1853    out_s = chroma / (r + 1e-20f);
   1854    out_v = r;
   1855}
   1856
   1857// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
   1858// also http://en.wikipedia.org/wiki/HSL_and_HSV
   1859void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
   1860{
   1861    if (s == 0.0f)
   1862    {
   1863        // gray
   1864        out_r = out_g = out_b = v;
   1865        return;
   1866    }
   1867
   1868    h = ImFmod(h, 1.0f) / (60.0f/360.0f);
   1869    int   i = (int)h;
   1870    float f = h - (float)i;
   1871    float p = v * (1.0f - s);
   1872    float q = v * (1.0f - s * f);
   1873    float t = v * (1.0f - s * (1.0f - f));
   1874
   1875    switch (i)
   1876    {
   1877    case 0: out_r = v; out_g = t; out_b = p; break;
   1878    case 1: out_r = q; out_g = v; out_b = p; break;
   1879    case 2: out_r = p; out_g = v; out_b = t; break;
   1880    case 3: out_r = p; out_g = q; out_b = v; break;
   1881    case 4: out_r = t; out_g = p; out_b = v; break;
   1882    case 5: default: out_r = v; out_g = p; out_b = q; break;
   1883    }
   1884}
   1885
   1886//-----------------------------------------------------------------------------
   1887// [SECTION] ImGuiStorage
   1888// Helper: Key->value storage
   1889//-----------------------------------------------------------------------------
   1890
   1891// std::lower_bound but without the bullshit
   1892static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)
   1893{
   1894    ImGuiStorage::ImGuiStoragePair* first = data.Data;
   1895    ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
   1896    size_t count = (size_t)(last - first);
   1897    while (count > 0)
   1898    {
   1899        size_t count2 = count >> 1;
   1900        ImGuiStorage::ImGuiStoragePair* mid = first + count2;
   1901        if (mid->key < key)
   1902        {
   1903            first = ++mid;
   1904            count -= count2 + 1;
   1905        }
   1906        else
   1907        {
   1908            count = count2;
   1909        }
   1910    }
   1911    return first;
   1912}
   1913
   1914// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
   1915void ImGuiStorage::BuildSortByKey()
   1916{
   1917    struct StaticFunc
   1918    {
   1919        static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
   1920        {
   1921            // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
   1922            if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
   1923            if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
   1924            return 0;
   1925        }
   1926    };
   1927    if (Data.Size > 1)
   1928        ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID);
   1929}
   1930
   1931int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
   1932{
   1933    ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
   1934    if (it == Data.end() || it->key != key)
   1935        return default_val;
   1936    return it->val_i;
   1937}
   1938
   1939bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
   1940{
   1941    return GetInt(key, default_val ? 1 : 0) != 0;
   1942}
   1943
   1944float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
   1945{
   1946    ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
   1947    if (it == Data.end() || it->key != key)
   1948        return default_val;
   1949    return it->val_f;
   1950}
   1951
   1952void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
   1953{
   1954    ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
   1955    if (it == Data.end() || it->key != key)
   1956        return NULL;
   1957    return it->val_p;
   1958}
   1959
   1960// 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.
   1961int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
   1962{
   1963    ImGuiStoragePair* it = LowerBound(Data, key);
   1964    if (it == Data.end() || it->key != key)
   1965        it = Data.insert(it, ImGuiStoragePair(key, default_val));
   1966    return &it->val_i;
   1967}
   1968
   1969bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
   1970{
   1971    return (bool*)GetIntRef(key, default_val ? 1 : 0);
   1972}
   1973
   1974float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
   1975{
   1976    ImGuiStoragePair* it = LowerBound(Data, key);
   1977    if (it == Data.end() || it->key != key)
   1978        it = Data.insert(it, ImGuiStoragePair(key, default_val));
   1979    return &it->val_f;
   1980}
   1981
   1982void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
   1983{
   1984    ImGuiStoragePair* it = LowerBound(Data, key);
   1985    if (it == Data.end() || it->key != key)
   1986        it = Data.insert(it, ImGuiStoragePair(key, default_val));
   1987    return &it->val_p;
   1988}
   1989
   1990// 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)
   1991void ImGuiStorage::SetInt(ImGuiID key, int val)
   1992{
   1993    ImGuiStoragePair* it = LowerBound(Data, key);
   1994    if (it == Data.end() || it->key != key)
   1995    {
   1996        Data.insert(it, ImGuiStoragePair(key, val));
   1997        return;
   1998    }
   1999    it->val_i = val;
   2000}
   2001
   2002void ImGuiStorage::SetBool(ImGuiID key, bool val)
   2003{
   2004    SetInt(key, val ? 1 : 0);
   2005}
   2006
   2007void ImGuiStorage::SetFloat(ImGuiID key, float val)
   2008{
   2009    ImGuiStoragePair* it = LowerBound(Data, key);
   2010    if (it == Data.end() || it->key != key)
   2011    {
   2012        Data.insert(it, ImGuiStoragePair(key, val));
   2013        return;
   2014    }
   2015    it->val_f = val;
   2016}
   2017
   2018void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
   2019{
   2020    ImGuiStoragePair* it = LowerBound(Data, key);
   2021    if (it == Data.end() || it->key != key)
   2022    {
   2023        Data.insert(it, ImGuiStoragePair(key, val));
   2024        return;
   2025    }
   2026    it->val_p = val;
   2027}
   2028
   2029void ImGuiStorage::SetAllInt(int v)
   2030{
   2031    for (int i = 0; i < Data.Size; i++)
   2032        Data[i].val_i = v;
   2033}
   2034
   2035//-----------------------------------------------------------------------------
   2036// [SECTION] ImGuiTextFilter
   2037//-----------------------------------------------------------------------------
   2038
   2039// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
   2040ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
   2041{
   2042    if (default_filter)
   2043    {
   2044        ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
   2045        Build();
   2046    }
   2047    else
   2048    {
   2049        InputBuf[0] = 0;
   2050        CountGrep = 0;
   2051    }
   2052}
   2053
   2054bool ImGuiTextFilter::Draw(const char* label, float width)
   2055{
   2056    if (width != 0.0f)
   2057        ImGui::SetNextItemWidth(width);
   2058    bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
   2059    if (value_changed)
   2060        Build();
   2061    return value_changed;
   2062}
   2063
   2064void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
   2065{
   2066    out->resize(0);
   2067    const char* wb = b;
   2068    const char* we = wb;
   2069    while (we < e)
   2070    {
   2071        if (*we == separator)
   2072        {
   2073            out->push_back(ImGuiTextRange(wb, we));
   2074            wb = we + 1;
   2075        }
   2076        we++;
   2077    }
   2078    if (wb != we)
   2079        out->push_back(ImGuiTextRange(wb, we));
   2080}
   2081
   2082void ImGuiTextFilter::Build()
   2083{
   2084    Filters.resize(0);
   2085    ImGuiTextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
   2086    input_range.split(',', &Filters);
   2087
   2088    CountGrep = 0;
   2089    for (int i = 0; i != Filters.Size; i++)
   2090    {
   2091        ImGuiTextRange& f = Filters[i];
   2092        while (f.b < f.e && ImCharIsBlankA(f.b[0]))
   2093            f.b++;
   2094        while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
   2095            f.e--;
   2096        if (f.empty())
   2097            continue;
   2098        if (Filters[i].b[0] != '-')
   2099            CountGrep += 1;
   2100    }
   2101}
   2102
   2103bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
   2104{
   2105    if (Filters.empty())
   2106        return true;
   2107
   2108    if (text == NULL)
   2109        text = "";
   2110
   2111    for (int i = 0; i != Filters.Size; i++)
   2112    {
   2113        const ImGuiTextRange& f = Filters[i];
   2114        if (f.empty())
   2115            continue;
   2116        if (f.b[0] == '-')
   2117        {
   2118            // Subtract
   2119            if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
   2120                return false;
   2121        }
   2122        else
   2123        {
   2124            // Grep
   2125            if (ImStristr(text, text_end, f.b, f.e) != NULL)
   2126                return true;
   2127        }
   2128    }
   2129
   2130    // Implicit * grep
   2131    if (CountGrep == 0)
   2132        return true;
   2133
   2134    return false;
   2135}
   2136
   2137//-----------------------------------------------------------------------------
   2138// [SECTION] ImGuiTextBuffer
   2139//-----------------------------------------------------------------------------
   2140
   2141// On some platform vsnprintf() takes va_list by reference and modifies it.
   2142// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
   2143#ifndef va_copy
   2144#if defined(__GNUC__) || defined(__clang__)
   2145#define va_copy(dest, src) __builtin_va_copy(dest, src)
   2146#else
   2147#define va_copy(dest, src) (dest = src)
   2148#endif
   2149#endif
   2150
   2151char ImGuiTextBuffer::EmptyString[1] = { 0 };
   2152
   2153void ImGuiTextBuffer::append(const char* str, const char* str_end)
   2154{
   2155    int len = str_end ? (int)(str_end - str) : (int)strlen(str);
   2156
   2157    // Add zero-terminator the first time
   2158    const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
   2159    const int needed_sz = write_off + len;
   2160    if (write_off + len >= Buf.Capacity)
   2161    {
   2162        int new_capacity = Buf.Capacity * 2;
   2163        Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
   2164    }
   2165
   2166    Buf.resize(needed_sz);
   2167    memcpy(&Buf[write_off - 1], str, (size_t)len);
   2168    Buf[write_off - 1 + len] = 0;
   2169}
   2170
   2171void ImGuiTextBuffer::appendf(const char* fmt, ...)
   2172{
   2173    va_list args;
   2174    va_start(args, fmt);
   2175    appendfv(fmt, args);
   2176    va_end(args);
   2177}
   2178
   2179// Helper: Text buffer for logging/accumulating text
   2180void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
   2181{
   2182    va_list args_copy;
   2183    va_copy(args_copy, args);
   2184
   2185    int len = ImFormatStringV(NULL, 0, fmt, args);         // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
   2186    if (len <= 0)
   2187    {
   2188        va_end(args_copy);
   2189        return;
   2190    }
   2191
   2192    // Add zero-terminator the first time
   2193    const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
   2194    const int needed_sz = write_off + len;
   2195    if (write_off + len >= Buf.Capacity)
   2196    {
   2197        int new_capacity = Buf.Capacity * 2;
   2198        Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
   2199    }
   2200
   2201    Buf.resize(needed_sz);
   2202    ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
   2203    va_end(args_copy);
   2204}
   2205
   2206//-----------------------------------------------------------------------------
   2207// [SECTION] ImGuiListClipper
   2208// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed
   2209// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO)
   2210//-----------------------------------------------------------------------------
   2211
   2212// Helper to calculate coarse clipping of large list of evenly sized items.
   2213// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
   2214// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
   2215void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
   2216{
   2217    ImGuiContext& g = *GImGui;
   2218    ImGuiWindow* window = g.CurrentWindow;
   2219    if (g.LogEnabled)
   2220    {
   2221        // If logging is active, do not perform any clipping
   2222        *out_items_display_start = 0;
   2223        *out_items_display_end = items_count;
   2224        return;
   2225    }
   2226    if (window->SkipItems)
   2227    {
   2228        *out_items_display_start = *out_items_display_end = 0;
   2229        return;
   2230    }
   2231
   2232    // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
   2233    ImRect unclipped_rect = window->ClipRect;
   2234    if (g.NavMoveRequest)
   2235        unclipped_rect.Add(g.NavScoringRect);
   2236    if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
   2237        unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max));
   2238
   2239    const ImVec2 pos = window->DC.CursorPos;
   2240    int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
   2241    int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
   2242
   2243    // When performing a navigation request, ensure we have one item extra in the direction we are moving to
   2244    if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
   2245        start--;
   2246    if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
   2247        end++;
   2248
   2249    start = ImClamp(start, 0, items_count);
   2250    end = ImClamp(end + 1, start, items_count);
   2251    *out_items_display_start = start;
   2252    *out_items_display_end = end;
   2253}
   2254
   2255static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
   2256{
   2257    // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
   2258    // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
   2259    // The clipper should probably have a 4th step to display the last item in a regular manner.
   2260    ImGuiContext& g = *GImGui;
   2261    ImGuiWindow* window = g.CurrentWindow;
   2262    window->DC.CursorPos.y = pos_y;
   2263    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y);
   2264    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.
   2265    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.
   2266    if (ImGuiColumns* columns = window->DC.CurrentColumns)
   2267        columns->LineMinY = window->DC.CursorPos.y;                         // Setting this so that cell Y position are set properly
   2268}
   2269
   2270// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
   2271// Use case B: Begin() called from constructor with items_height>0
   2272// 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.
   2273void ImGuiListClipper::Begin(int count, float items_height)
   2274{
   2275    ImGuiContext& g = *GImGui;
   2276    ImGuiWindow* window = g.CurrentWindow;
   2277
   2278    StartPosY = window->DC.CursorPos.y;
   2279    ItemsHeight = items_height;
   2280    ItemsCount = count;
   2281    StepNo = 0;
   2282    DisplayEnd = DisplayStart = -1;
   2283    if (ItemsHeight > 0.0f)
   2284    {
   2285        ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
   2286        if (DisplayStart > 0)
   2287            SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
   2288        StepNo = 2;
   2289    }
   2290}
   2291
   2292void ImGuiListClipper::End()
   2293{
   2294    if (ItemsCount < 0)
   2295        return;
   2296    // 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.
   2297    if (ItemsCount < INT_MAX)
   2298        SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
   2299    ItemsCount = -1;
   2300    StepNo = 3;
   2301}
   2302
   2303bool ImGuiListClipper::Step()
   2304{
   2305    ImGuiContext& g = *GImGui;
   2306    ImGuiWindow* window = g.CurrentWindow;
   2307
   2308    if (ItemsCount == 0 || window->SkipItems)
   2309    {
   2310        ItemsCount = -1;
   2311        return false;
   2312    }
   2313    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.
   2314    {
   2315        DisplayStart = 0;
   2316        DisplayEnd = 1;
   2317        StartPosY = window->DC.CursorPos.y;
   2318        StepNo = 1;
   2319        return true;
   2320    }
   2321    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.
   2322    {
   2323        if (ItemsCount == 1) { ItemsCount = -1; return false; }
   2324        float items_height = window->DC.CursorPos.y - StartPosY;
   2325        IM_ASSERT(items_height > 0.0f);   // If this triggers, it means Item 0 hasn't moved the cursor vertically
   2326        Begin(ItemsCount - 1, items_height);
   2327        DisplayStart++;
   2328        DisplayEnd++;
   2329        StepNo = 3;
   2330        return true;
   2331    }
   2332    if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3.
   2333    {
   2334        IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
   2335        StepNo = 3;
   2336        return true;
   2337    }
   2338    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.
   2339        End();
   2340    return false;
   2341}
   2342
   2343//-----------------------------------------------------------------------------
   2344// [SECTION] STYLING
   2345//-----------------------------------------------------------------------------
   2346
   2347ImGuiStyle& ImGui::GetStyle()
   2348{
   2349    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
   2350    return GImGui->Style;
   2351}
   2352
   2353ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
   2354{
   2355    ImGuiStyle& style = GImGui->Style;
   2356    ImVec4 c = style.Colors[idx];
   2357    c.w *= style.Alpha * alpha_mul;
   2358    return ColorConvertFloat4ToU32(c);
   2359}
   2360
   2361ImU32 ImGui::GetColorU32(const ImVec4& col)
   2362{
   2363    ImGuiStyle& style = GImGui->Style;
   2364    ImVec4 c = col;
   2365    c.w *= style.Alpha;
   2366    return ColorConvertFloat4ToU32(c);
   2367}
   2368
   2369const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
   2370{
   2371    ImGuiStyle& style = GImGui->Style;
   2372    return style.Colors[idx];
   2373}
   2374
   2375ImU32 ImGui::GetColorU32(ImU32 col)
   2376{
   2377    ImGuiStyle& style = GImGui->Style;
   2378    if (style.Alpha >= 1.0f)
   2379        return col;
   2380    ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
   2381    a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
   2382    return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
   2383}
   2384
   2385// 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
   2386void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)
   2387{
   2388    ImGuiContext& g = *GImGui;
   2389    ImGuiColorMod backup;
   2390    backup.Col = idx;
   2391    backup.BackupValue = g.Style.Colors[idx];
   2392    g.ColorModifiers.push_back(backup);
   2393    g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
   2394}
   2395
   2396void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
   2397{
   2398    ImGuiContext& g = *GImGui;
   2399    ImGuiColorMod backup;
   2400    backup.Col = idx;
   2401    backup.BackupValue = g.Style.Colors[idx];
   2402    g.ColorModifiers.push_back(backup);
   2403    g.Style.Colors[idx] = col;
   2404}
   2405
   2406void ImGui::PopStyleColor(int count)
   2407{
   2408    ImGuiContext& g = *GImGui;
   2409    while (count > 0)
   2410    {
   2411        ImGuiColorMod& backup = g.ColorModifiers.back();
   2412        g.Style.Colors[backup.Col] = backup.BackupValue;
   2413        g.ColorModifiers.pop_back();
   2414        count--;
   2415    }
   2416}
   2417
   2418struct ImGuiStyleVarInfo
   2419{
   2420    ImGuiDataType   Type;
   2421    ImU32           Count;
   2422    ImU32           Offset;
   2423    void*           GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
   2424};
   2425
   2426static const ImGuiStyleVarInfo GStyleVarInfo[] =
   2427{
   2428    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) },               // ImGuiStyleVar_Alpha
   2429    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) },       // ImGuiStyleVar_WindowPadding
   2430    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) },      // ImGuiStyleVar_WindowRounding
   2431    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) },    // ImGuiStyleVar_WindowBorderSize
   2432    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) },       // ImGuiStyleVar_WindowMinSize
   2433    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) },    // ImGuiStyleVar_WindowTitleAlign
   2434    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) },       // ImGuiStyleVar_ChildRounding
   2435    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) },     // ImGuiStyleVar_ChildBorderSize
   2436    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) },       // ImGuiStyleVar_PopupRounding
   2437    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) },     // ImGuiStyleVar_PopupBorderSize
   2438    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) },        // ImGuiStyleVar_FramePadding
   2439    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) },       // ImGuiStyleVar_FrameRounding
   2440    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) },     // ImGuiStyleVar_FrameBorderSize
   2441    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) },         // ImGuiStyleVar_ItemSpacing
   2442    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) },    // ImGuiStyleVar_ItemInnerSpacing
   2443    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },       // ImGuiStyleVar_IndentSpacing
   2444    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) },       // ImGuiStyleVar_ScrollbarSize
   2445    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) },   // ImGuiStyleVar_ScrollbarRounding
   2446    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },         // ImGuiStyleVar_GrabMinSize
   2447    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) },        // ImGuiStyleVar_GrabRounding
   2448    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) },         // ImGuiStyleVar_TabRounding
   2449    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },     // ImGuiStyleVar_ButtonTextAlign
   2450    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
   2451};
   2452
   2453static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
   2454{
   2455    IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
   2456    IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
   2457    return &GStyleVarInfo[idx];
   2458}
   2459
   2460void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
   2461{
   2462    const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
   2463    if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
   2464    {
   2465        ImGuiContext& g = *GImGui;
   2466        float* pvar = (float*)var_info->GetVarPtr(&g.Style);
   2467        g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
   2468        *pvar = val;
   2469        return;
   2470    }
   2471    IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");
   2472}
   2473
   2474void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
   2475{
   2476    const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
   2477    if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
   2478    {
   2479        ImGuiContext& g = *GImGui;
   2480        ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
   2481        g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
   2482        *pvar = val;
   2483        return;
   2484    }
   2485    IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");
   2486}
   2487
   2488void ImGui::PopStyleVar(int count)
   2489{
   2490    ImGuiContext& g = *GImGui;
   2491    while (count > 0)
   2492    {
   2493        // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
   2494        ImGuiStyleMod& backup = g.StyleModifiers.back();
   2495        const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
   2496        void* data = info->GetVarPtr(&g.Style);
   2497        if (info->Type == ImGuiDataType_Float && info->Count == 1)      { ((float*)data)[0] = backup.BackupFloat[0]; }
   2498        else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
   2499        g.StyleModifiers.pop_back();
   2500        count--;
   2501    }
   2502}
   2503
   2504const char* ImGui::GetStyleColorName(ImGuiCol idx)
   2505{
   2506    // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
   2507    switch (idx)
   2508    {
   2509    case ImGuiCol_Text: return "Text";
   2510    case ImGuiCol_TextDisabled: return "TextDisabled";
   2511    case ImGuiCol_WindowBg: return "WindowBg";
   2512    case ImGuiCol_ChildBg: return "ChildBg";
   2513    case ImGuiCol_PopupBg: return "PopupBg";
   2514    case ImGuiCol_Border: return "Border";
   2515    case ImGuiCol_BorderShadow: return "BorderShadow";
   2516    case ImGuiCol_FrameBg: return "FrameBg";
   2517    case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
   2518    case ImGuiCol_FrameBgActive: return "FrameBgActive";
   2519    case ImGuiCol_TitleBg: return "TitleBg";
   2520    case ImGuiCol_TitleBgActive: return "TitleBgActive";
   2521    case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
   2522    case ImGuiCol_MenuBarBg: return "MenuBarBg";
   2523    case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
   2524    case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
   2525    case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
   2526    case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
   2527    case ImGuiCol_CheckMark: return "CheckMark";
   2528    case ImGuiCol_SliderGrab: return "SliderGrab";
   2529    case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
   2530    case ImGuiCol_Button: return "Button";
   2531    case ImGuiCol_ButtonHovered: return "ButtonHovered";
   2532    case ImGuiCol_ButtonActive: return "ButtonActive";
   2533    case ImGuiCol_Header: return "Header";
   2534    case ImGuiCol_HeaderHovered: return "HeaderHovered";
   2535    case ImGuiCol_HeaderActive: return "HeaderActive";
   2536    case ImGuiCol_Separator: return "Separator";
   2537    case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
   2538    case ImGuiCol_SeparatorActive: return "SeparatorActive";
   2539    case ImGuiCol_ResizeGrip: return "ResizeGrip";
   2540    case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
   2541    case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
   2542    case ImGuiCol_Tab: return "Tab";
   2543    case ImGuiCol_TabHovered: return "TabHovered";
   2544    case ImGuiCol_TabActive: return "TabActive";
   2545    case ImGuiCol_TabUnfocused: return "TabUnfocused";
   2546    case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
   2547    case ImGuiCol_PlotLines: return "PlotLines";
   2548    case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
   2549    case ImGuiCol_PlotHistogram: return "PlotHistogram";
   2550    case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
   2551    case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
   2552    case ImGuiCol_DragDropTarget: return "DragDropTarget";
   2553    case ImGuiCol_NavHighlight: return "NavHighlight";
   2554    case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
   2555    case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
   2556    case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
   2557    }
   2558    IM_ASSERT(0);
   2559    return "Unknown";
   2560}
   2561
   2562//-----------------------------------------------------------------------------
   2563// [SECTION] RENDER HELPERS
   2564// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change,
   2565// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context.
   2566// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context.
   2567//-----------------------------------------------------------------------------
   2568
   2569const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
   2570{
   2571    const char* text_display_end = text;
   2572    if (!text_end)
   2573        text_end = (const char*)-1;
   2574
   2575    while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
   2576        text_display_end++;
   2577    return text_display_end;
   2578}
   2579
   2580// Internal ImGui functions to render text
   2581// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
   2582void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
   2583{
   2584    ImGuiContext& g = *GImGui;
   2585    ImGuiWindow* window = g.CurrentWindow;
   2586
   2587    // Hide anything after a '##' string
   2588    const char* text_display_end;
   2589    if (hide_text_after_hash)
   2590    {
   2591        text_display_end = FindRenderedTextEnd(text, text_end);
   2592    }
   2593    else
   2594    {
   2595        if (!text_end)
   2596            text_end = text + strlen(text); // FIXME-OPT
   2597        text_display_end = text_end;
   2598    }
   2599
   2600    if (text != text_display_end)
   2601    {
   2602        window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
   2603        if (g.LogEnabled)
   2604            LogRenderedText(&pos, text, text_display_end);
   2605    }
   2606}
   2607
   2608void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
   2609{
   2610    ImGuiContext& g = *GImGui;
   2611    ImGuiWindow* window = g.CurrentWindow;
   2612
   2613    if (!text_end)
   2614        text_end = text + strlen(text); // FIXME-OPT
   2615
   2616    if (text != text_end)
   2617    {
   2618        window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
   2619        if (g.LogEnabled)
   2620            LogRenderedText(&pos, text, text_end);
   2621    }
   2622}
   2623
   2624// Default clip_rect uses (pos_min,pos_max)
   2625// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
   2626void 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)
   2627{
   2628    // Perform CPU side clipping for single clipped element to avoid using scissor state
   2629    ImVec2 pos = pos_min;
   2630    const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
   2631
   2632    const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
   2633    const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
   2634    bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
   2635    if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
   2636        need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
   2637
   2638    // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
   2639    if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
   2640    if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
   2641
   2642    // Render
   2643    if (need_clipping)
   2644    {
   2645        ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
   2646        draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
   2647    }
   2648    else
   2649    {
   2650        draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
   2651    }
   2652}
   2653
   2654void 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)
   2655{
   2656    // Hide anything after a '##' string
   2657    const char* text_display_end = FindRenderedTextEnd(text, text_end);
   2658    const int text_len = (int)(text_display_end - text);
   2659    if (text_len == 0)
   2660        return;
   2661
   2662    ImGuiContext& g = *GImGui;
   2663    ImGuiWindow* window = g.CurrentWindow;
   2664    RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
   2665    if (g.LogEnabled)
   2666        LogRenderedText(&pos_min, text, text_display_end);
   2667}
   2668
   2669
   2670// Another overly complex function until we reorganize everything into a nice all-in-one helper.
   2671// 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.
   2672// 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.
   2673void 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)
   2674{
   2675    ImGuiContext& g = *GImGui;
   2676    if (text_end_full == NULL)
   2677        text_end_full = FindRenderedTextEnd(text);
   2678    const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
   2679
   2680    //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));
   2681    //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));
   2682    //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));
   2683    // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
   2684    if (text_size.x > pos_max.x - pos_min.x)
   2685    {
   2686        // Hello wo...
   2687        // |       |   |
   2688        // min   max   ellipsis_max
   2689        //          <-> this is generally some padding value
   2690
   2691        const ImFont* font = draw_list->_Data->Font;
   2692        const float font_size = draw_list->_Data->FontSize;
   2693        const char* text_end_ellipsis = NULL;
   2694
   2695        ImWchar ellipsis_char = font->EllipsisChar;
   2696        int ellipsis_char_count = 1;
   2697        if (ellipsis_char == (ImWchar)-1)
   2698        {
   2699            ellipsis_char = (ImWchar)'.';
   2700            ellipsis_char_count = 3;
   2701        }
   2702        const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
   2703
   2704        float ellipsis_glyph_width = glyph->X1;                 // Width of the glyph with no padding on either side
   2705        float ellipsis_total_width = ellipsis_glyph_width;      // Full width of entire ellipsis
   2706
   2707        if (ellipsis_char_count > 1)
   2708        {
   2709            // Full ellipsis size without free spacing after it.
   2710            const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize);
   2711            ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
   2712            ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
   2713        }
   2714
   2715        // We can now claim the space between pos_max.x and ellipsis_max.x
   2716        const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f);
   2717        float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
   2718        if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
   2719        {
   2720            // Always display at least 1 character if there's no room for character + ellipsis
   2721            text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
   2722            text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
   2723        }
   2724        while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
   2725        {
   2726            // 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)
   2727            text_end_ellipsis--;
   2728            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
   2729        }
   2730
   2731        // Render text, render ellipsis
   2732        RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
   2733        float ellipsis_x = pos_min.x + text_size_clipped_x;
   2734        if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x)
   2735            for (int i = 0; i < ellipsis_char_count; i++)
   2736            {
   2737                font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char);
   2738                ellipsis_x += ellipsis_glyph_width;
   2739            }
   2740    }
   2741    else
   2742    {
   2743        RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
   2744    }
   2745
   2746    if (g.LogEnabled)
   2747        LogRenderedText(&pos_min, text, text_end_full);
   2748}
   2749
   2750// Render a rectangle shaped with optional rounding and borders
   2751void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
   2752{
   2753    ImGuiContext& g = *GImGui;
   2754    ImGuiWindow* window = g.CurrentWindow;
   2755    window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
   2756    const float border_size = g.Style.FrameBorderSize;
   2757    if (border && border_size > 0.0f)
   2758    {
   2759        window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
   2760        window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
   2761    }
   2762}
   2763
   2764void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
   2765{
   2766    ImGuiContext& g = *GImGui;
   2767    ImGuiWindow* window = g.CurrentWindow;
   2768    const float border_size = g.Style.FrameBorderSize;
   2769    if (border_size > 0.0f)
   2770    {
   2771        window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
   2772        window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
   2773    }
   2774}
   2775
   2776void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)
   2777{
   2778    ImGuiContext& g = *GImGui;
   2779    if (id != g.NavId)
   2780        return;
   2781    if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
   2782        return;
   2783    ImGuiWindow* window = g.CurrentWindow;
   2784    if (window->DC.NavHideHighlightOneFrame)
   2785        return;
   2786
   2787    float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
   2788    ImRect display_rect = bb;
   2789    display_rect.ClipWith(window->ClipRect);
   2790    if (flags & ImGuiNavHighlightFlags_TypeDefault)
   2791    {
   2792        const float THICKNESS = 2.0f;
   2793        const float DISTANCE = 3.0f + THICKNESS * 0.5f;
   2794        display_rect.Expand(ImVec2(DISTANCE,DISTANCE));
   2795        bool fully_visible = window->ClipRect.Contains(display_rect);
   2796        if (!fully_visible)
   2797            window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
   2798        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);
   2799        if (!fully_visible)
   2800            window->DrawList->PopClipRect();
   2801    }
   2802    if (flags & ImGuiNavHighlightFlags_TypeThin)
   2803    {
   2804        window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f);
   2805    }
   2806}
   2807
   2808//-----------------------------------------------------------------------------
   2809// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
   2810//-----------------------------------------------------------------------------
   2811
   2812// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
   2813ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
   2814    : DrawListInst(&context->DrawListSharedData)
   2815{
   2816    Name = ImStrdup(name);
   2817    ID = ImHashStr(name);
   2818    IDStack.push_back(ID);
   2819    Flags = ImGuiWindowFlags_None;
   2820    Pos = ImVec2(0.0f, 0.0f);
   2821    Size = SizeFull = ImVec2(0.0f, 0.0f);
   2822    ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f);
   2823    WindowPadding = ImVec2(0.0f, 0.0f);
   2824    WindowRounding = 0.0f;
   2825    WindowBorderSize = 0.0f;
   2826    NameBufLen = (int)strlen(name) + 1;
   2827    MoveId = GetID("#MOVE");
   2828    ChildId = 0;
   2829    Scroll = ImVec2(0.0f, 0.0f);
   2830    ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
   2831    ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
   2832    ScrollbarSizes = ImVec2(0.0f, 0.0f);
   2833    ScrollbarX = ScrollbarY = false;
   2834    Active = WasActive = false;
   2835    WriteAccessed = false;
   2836    Collapsed = false;
   2837    WantCollapseToggle = false;
   2838    SkipItems = false;
   2839    Appearing = false;
   2840    Hidden = false;
   2841    IsFallbackWindow = false;
   2842    HasCloseButton = false;
   2843    ResizeBorderHeld = -1;
   2844    BeginCount = 0;
   2845    BeginOrderWithinParent = -1;
   2846    BeginOrderWithinContext = -1;
   2847    PopupId = 0;
   2848    AutoFitFramesX = AutoFitFramesY = -1;
   2849    AutoFitChildAxises = 0x00;
   2850    AutoFitOnlyGrows = false;
   2851    AutoPosLastDirection = ImGuiDir_None;
   2852    HiddenFramesCanSkipItems = HiddenFramesCannotSkipItems = 0;
   2853    SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
   2854    SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
   2855
   2856    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.
   2857
   2858    LastFrameActive = -1;
   2859    LastTimeActive = -1.0f;
   2860    ItemWidthDefault = 0.0f;
   2861    FontWindowScale = 1.0f;
   2862    SettingsOffset = -1;
   2863
   2864    DrawList = &DrawListInst;
   2865    DrawList->_OwnerName = Name;
   2866    ParentWindow = NULL;
   2867    RootWindow = NULL;
   2868    RootWindowForTitleBarHighlight = NULL;
   2869    RootWindowForNav = NULL;
   2870
   2871    NavLastIds[0] = NavLastIds[1] = 0;
   2872    NavRectRel[0] = NavRectRel[1] = ImRect();
   2873    NavLastChildNavWindow = NULL;
   2874
   2875    MemoryCompacted = false;
   2876    MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0;
   2877}
   2878
   2879ImGuiWindow::~ImGuiWindow()
   2880{
   2881    IM_ASSERT(DrawList == &DrawListInst);
   2882    IM_DELETE(Name);
   2883    for (int i = 0; i != ColumnsStorage.Size; i++)
   2884        ColumnsStorage[i].~ImGuiColumns();
   2885}
   2886
   2887ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
   2888{
   2889    ImGuiID seed = IDStack.back();
   2890    ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
   2891    ImGui::KeepAliveID(id);
   2892    return id;
   2893}
   2894
   2895ImGuiID ImGuiWindow::GetID(const void* ptr)
   2896{
   2897    ImGuiID seed = IDStack.back();
   2898    ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
   2899    ImGui::KeepAliveID(id);
   2900    return id;
   2901}
   2902
   2903ImGuiID ImGuiWindow::GetID(int n)
   2904{
   2905    ImGuiID seed = IDStack.back();
   2906    ImGuiID id = ImHashData(&n, sizeof(n), seed);
   2907    ImGui::KeepAliveID(id);
   2908    return id;
   2909}
   2910
   2911ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
   2912{
   2913    ImGuiID seed = IDStack.back();
   2914    return ImHashStr(str, str_end ? (str_end - str) : 0, seed);
   2915}
   2916
   2917ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
   2918{
   2919    ImGuiID seed = IDStack.back();
   2920    return ImHashData(&ptr, sizeof(void*), seed);
   2921}
   2922
   2923ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
   2924{
   2925    ImGuiID seed = IDStack.back();
   2926    return ImHashData(&n, sizeof(n), seed);
   2927}
   2928
   2929// This is only used in rare/specific situations to manufacture an ID out of nowhere.
   2930ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
   2931{
   2932    ImGuiID seed = IDStack.back();
   2933    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) };
   2934    ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
   2935    ImGui::KeepAliveID(id);
   2936    return id;
   2937}
   2938
   2939static void SetCurrentWindow(ImGuiWindow* window)
   2940{
   2941    ImGuiContext& g = *GImGui;
   2942    g.CurrentWindow = window;
   2943    if (window)
   2944        g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
   2945}
   2946
   2947// Free up/compact internal window buffers, we can use this when a window becomes unused.
   2948// This is currently unused by the library, but you may call this yourself for easy GC.
   2949// Not freed:
   2950// - ImGuiWindow, ImGuiWindowSettings, Name
   2951// - StateStorage, ColumnsStorage (may hold useful data)
   2952// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
   2953void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
   2954{
   2955    window->MemoryCompacted = true;
   2956    window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
   2957    window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
   2958    window->IDStack.clear();
   2959    window->DrawList->ClearFreeMemory();
   2960    window->DC.ChildWindows.clear();
   2961    window->DC.ItemFlagsStack.clear();
   2962    window->DC.ItemWidthStack.clear();
   2963    window->DC.TextWrapPosStack.clear();
   2964    window->DC.GroupStack.clear();
   2965}
   2966
   2967void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
   2968{
   2969    // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
   2970    // The other buffers tends to amortize much faster.
   2971    window->MemoryCompacted = false;
   2972    window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);
   2973    window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);
   2974    window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;
   2975}
   2976
   2977void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
   2978{
   2979    ImGuiContext& g = *GImGui;
   2980    g.ActiveIdIsJustActivated = (g.ActiveId != id);
   2981    if (g.ActiveIdIsJustActivated)
   2982    {
   2983        g.ActiveIdTimer = 0.0f;
   2984        g.ActiveIdHasBeenPressedBefore = false;
   2985        g.ActiveIdHasBeenEditedBefore = false;
   2986        if (id != 0)
   2987        {
   2988            g.LastActiveId = id;
   2989            g.LastActiveIdTimer = 0.0f;
   2990        }
   2991    }
   2992    g.ActiveId = id;
   2993    g.ActiveIdAllowOverlap = false;
   2994    g.ActiveIdWindow = window;
   2995    g.ActiveIdHasBeenEditedThisFrame = false;
   2996    if (id)
   2997    {
   2998        g.ActiveIdIsAlive = id;
   2999        g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
   3000    }
   3001
   3002    // Clear declaration of inputs claimed by the widget
   3003    // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
   3004    g.ActiveIdUsingNavDirMask = 0x00;
   3005    g.ActiveIdUsingNavInputMask = 0x00;
   3006    g.ActiveIdUsingKeyInputMask = 0x00;
   3007}
   3008
   3009void ImGui::ClearActiveID()
   3010{
   3011    SetActiveID(0, NULL);
   3012}
   3013
   3014void ImGui::SetHoveredID(ImGuiID id)
   3015{
   3016    ImGuiContext& g = *GImGui;
   3017    g.HoveredId = id;
   3018    g.HoveredIdAllowOverlap = false;
   3019    if (id != 0 && g.HoveredIdPreviousFrame != id)
   3020        g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;
   3021}
   3022
   3023ImGuiID ImGui::GetHoveredID()
   3024{
   3025    ImGuiContext& g = *GImGui;
   3026    return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
   3027}
   3028
   3029void ImGui::KeepAliveID(ImGuiID id)
   3030{
   3031    ImGuiContext& g = *GImGui;
   3032    if (g.ActiveId == id)
   3033        g.ActiveIdIsAlive = id;
   3034    if (g.ActiveIdPreviousFrame == id)
   3035        g.ActiveIdPreviousFrameIsAlive = true;
   3036}
   3037
   3038void ImGui::MarkItemEdited(ImGuiID id)
   3039{
   3040    // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
   3041    // 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.
   3042    ImGuiContext& g = *GImGui;
   3043    IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
   3044    IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
   3045    //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
   3046    g.ActiveIdHasBeenEditedThisFrame = true;
   3047    g.ActiveIdHasBeenEditedBefore = true;
   3048    g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
   3049}
   3050
   3051static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
   3052{
   3053    // An active popup disable hovering on other windows (apart from its own children)
   3054    // FIXME-OPT: This could be cached/stored within the window.
   3055    ImGuiContext& g = *GImGui;
   3056    if (g.NavWindow)
   3057        if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
   3058            if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
   3059            {
   3060                // For the purpose of those flags we differentiate "standard popup" from "modal popup"
   3061                // NB: The order of those two tests is important because Modal windows are also Popups.
   3062                if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
   3063                    return false;
   3064                if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
   3065                    return false;
   3066            }
   3067    return true;
   3068}
   3069
   3070// This is roughly matching the behavior of internal-facing ItemHoverable()
   3071// - 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()
   3072// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
   3073bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
   3074{
   3075    ImGuiContext& g = *GImGui;
   3076    ImGuiWindow* window = g.CurrentWindow;
   3077    if (g.NavDisableMouseHover && !g.NavDisableHighlight)
   3078        return IsItemFocused();
   3079
   3080    // Test for bounding box overlap, as updated as ItemAdd()
   3081    if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
   3082        return false;
   3083    IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0);   // Flags not supported by this function
   3084
   3085    // Test if we are hovering the right window (our window could be behind another window)
   3086    // [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.
   3087    // 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.
   3088    //if (g.HoveredWindow != window)
   3089    //    return false;
   3090    if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
   3091        return false;
   3092
   3093    // Test if another item is active (e.g. being dragged)
   3094    if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
   3095        if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
   3096            return false;
   3097
   3098    // Test if interactions on this window are blocked by an active popup or modal.
   3099    // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
   3100    if (!IsWindowContentHoverable(window, flags))
   3101        return false;
   3102
   3103    // Test if the item is disabled
   3104    if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
   3105        return false;
   3106
   3107    // Special handling for the dummy item after Begin() which represent the title bar or tab.
   3108    // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
   3109    if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
   3110        return false;
   3111    return true;
   3112}
   3113
   3114// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
   3115bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
   3116{
   3117    ImGuiContext& g = *GImGui;
   3118    if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
   3119        return false;
   3120
   3121    ImGuiWindow* window = g.CurrentWindow;
   3122    if (g.HoveredWindow != window)
   3123        return false;
   3124    if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
   3125        return false;
   3126    if (!IsMouseHoveringRect(bb.Min, bb.Max))
   3127        return false;
   3128    if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
   3129        return false;
   3130    if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
   3131        return false;
   3132
   3133    SetHoveredID(id);
   3134
   3135    // [DEBUG] Item Picker tool!
   3136    // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making
   3137    // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered
   3138    // items if we perform the test in ItemAdd(), but that would incur a small runtime cost.
   3139    // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd().
   3140    if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id)
   3141        GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
   3142    if (g.DebugItemPickerBreakId == id)
   3143        IM_DEBUG_BREAK();
   3144
   3145    return true;
   3146}
   3147
   3148bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
   3149{
   3150    ImGuiContext& g = *GImGui;
   3151    ImGuiWindow* window = g.CurrentWindow;
   3152    if (!bb.Overlaps(window->ClipRect))
   3153        if (id == 0 || (id != g.ActiveId && id != g.NavId))
   3154            if (clip_even_when_logged || !g.LogEnabled)
   3155                return true;
   3156    return false;
   3157}
   3158
   3159// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
   3160bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
   3161{
   3162    ImGuiContext& g = *GImGui;
   3163
   3164    // Increment counters
   3165    const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
   3166    window->DC.FocusCounterRegular++;
   3167    if (is_tab_stop)
   3168        window->DC.FocusCounterTabStop++;
   3169
   3170    // Process TAB/Shift-TAB to tab *OUT* of the currently focused item.
   3171    // (Note that we can always TAB out of a widget that doesn't allow tabbing in)
   3172    if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL)
   3173    {
   3174        g.FocusRequestNextWindow = window;
   3175        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.
   3176    }
   3177
   3178    // Handle focus requests
   3179    if (g.FocusRequestCurrWindow == window)
   3180    {
   3181        if (window->DC.FocusCounterRegular == g.FocusRequestCurrCounterRegular)
   3182            return true;
   3183        if (is_tab_stop && window->DC.FocusCounterTabStop == g.FocusRequestCurrCounterTabStop)
   3184        {
   3185            g.NavJustTabbedId = id;
   3186            return true;
   3187        }
   3188
   3189        // If another item is about to be focused, we clear our own active id
   3190        if (g.ActiveId == id)
   3191            ClearActiveID();
   3192    }
   3193
   3194    return false;
   3195}
   3196
   3197void ImGui::FocusableItemUnregister(ImGuiWindow* window)
   3198{
   3199    window->DC.FocusCounterRegular--;
   3200    window->DC.FocusCounterTabStop--;
   3201}
   3202
   3203float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
   3204{
   3205    if (wrap_pos_x < 0.0f)
   3206        return 0.0f;
   3207
   3208    ImGuiWindow* window = GImGui->CurrentWindow;
   3209    if (wrap_pos_x == 0.0f)
   3210        wrap_pos_x = window->WorkRect.Max.x;
   3211    else if (wrap_pos_x > 0.0f)
   3212        wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
   3213
   3214    return ImMax(wrap_pos_x - pos.x, 1.0f);
   3215}
   3216
   3217// IM_ALLOC() == ImGui::MemAlloc()
   3218void* ImGui::MemAlloc(size_t size)
   3219{
   3220    if (ImGuiContext* ctx = GImGui)
   3221        ctx->IO.MetricsActiveAllocations++;
   3222    return GImAllocatorAllocFunc(size, GImAllocatorUserData);
   3223}
   3224
   3225// IM_FREE() == ImGui::MemFree()
   3226void ImGui::MemFree(void* ptr)
   3227{
   3228    if (ptr)
   3229        if (ImGuiContext* ctx = GImGui)
   3230            ctx->IO.MetricsActiveAllocations--;
   3231    return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
   3232}
   3233
   3234const char* ImGui::GetClipboardText()
   3235{
   3236    ImGuiContext& g = *GImGui;
   3237    return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : "";
   3238}
   3239
   3240void ImGui::SetClipboardText(const char* text)
   3241{
   3242    ImGuiContext& g = *GImGui;
   3243    if (g.IO.SetClipboardTextFn)
   3244        g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text);
   3245}
   3246
   3247const char* ImGui::GetVersion()
   3248{
   3249    return IMGUI_VERSION;
   3250}
   3251
   3252// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
   3253// 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
   3254ImGuiContext* ImGui::GetCurrentContext()
   3255{
   3256    return GImGui;
   3257}
   3258
   3259void ImGui::SetCurrentContext(ImGuiContext* ctx)
   3260{
   3261#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
   3262    IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
   3263#else
   3264    GImGui = ctx;
   3265#endif
   3266}
   3267
   3268void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
   3269{
   3270    GImAllocatorAllocFunc = alloc_func;
   3271    GImAllocatorFreeFunc = free_func;
   3272    GImAllocatorUserData = user_data;
   3273}
   3274
   3275ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
   3276{
   3277    ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
   3278    if (GImGui == NULL)
   3279        SetCurrentContext(ctx);
   3280    Initialize(ctx);
   3281    return ctx;
   3282}
   3283
   3284void ImGui::DestroyContext(ImGuiContext* ctx)
   3285{
   3286    if (ctx == NULL)
   3287        ctx = GImGui;
   3288    Shutdown(ctx);
   3289    if (GImGui == ctx)
   3290        SetCurrentContext(NULL);
   3291    IM_DELETE(ctx);
   3292}
   3293
   3294ImGuiIO& ImGui::GetIO()
   3295{
   3296    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
   3297    return GImGui->IO;
   3298}
   3299
   3300// Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame()
   3301ImDrawData* ImGui::GetDrawData()
   3302{
   3303    ImGuiContext& g = *GImGui;
   3304    return g.DrawData.Valid ? &g.DrawData : NULL;
   3305}
   3306
   3307double ImGui::GetTime()
   3308{
   3309    return GImGui->Time;
   3310}
   3311
   3312int ImGui::GetFrameCount()
   3313{
   3314    return GImGui->FrameCount;
   3315}
   3316
   3317ImDrawList* ImGui::GetBackgroundDrawList()
   3318{
   3319    return &GImGui->BackgroundDrawList;
   3320}
   3321
   3322ImDrawList* ImGui::GetForegroundDrawList()
   3323{
   3324    return &GImGui->ForegroundDrawList;
   3325}
   3326
   3327ImDrawListSharedData* ImGui::GetDrawListSharedData()
   3328{
   3329    return &GImGui->DrawListSharedData;
   3330}
   3331
   3332void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
   3333{
   3334    // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
   3335    // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
   3336    // This is because we want ActiveId to be set even when the window is not permitted to move.
   3337    ImGuiContext& g = *GImGui;
   3338    FocusWindow(window);
   3339    SetActiveID(window->MoveId, window);
   3340    g.NavDisableHighlight = true;
   3341    g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos;
   3342
   3343    bool can_move_window = true;
   3344    if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove))
   3345        can_move_window = false;
   3346    if (can_move_window)
   3347        g.MovingWindow = window;
   3348}
   3349
   3350// Handle mouse moving window
   3351// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
   3352// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId.
   3353// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs,
   3354// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other.
   3355void ImGui::UpdateMouseMovingWindowNewFrame()
   3356{
   3357    ImGuiContext& g = *GImGui;
   3358    if (g.MovingWindow != NULL)
   3359    {
   3360        // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
   3361        // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
   3362        KeepAliveID(g.ActiveId);
   3363        IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);
   3364        ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
   3365        if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
   3366        {
   3367            ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
   3368            if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
   3369            {
   3370                MarkIniSettingsDirty(moving_window);
   3371                SetWindowPos(moving_window, pos, ImGuiCond_Always);
   3372            }
   3373            FocusWindow(g.MovingWindow);
   3374        }
   3375        else
   3376        {
   3377            ClearActiveID();
   3378            g.MovingWindow = NULL;
   3379        }
   3380    }
   3381    else
   3382    {
   3383        // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
   3384        if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
   3385        {
   3386            KeepAliveID(g.ActiveId);
   3387            if (!g.IO.MouseDown[0])
   3388                ClearActiveID();
   3389        }
   3390    }
   3391}
   3392
   3393// Initiate moving window when clicking on empty space or title bar.
   3394// Handle left-click and right-click focus.
   3395void ImGui::UpdateMouseMovingWindowEndFrame()
   3396{
   3397    ImGuiContext& g = *GImGui;
   3398    if (g.ActiveId != 0 || g.HoveredId != 0)
   3399        return;
   3400
   3401    // Unless we just made a window/popup appear
   3402    if (g.NavWindow && g.NavWindow->Appearing)
   3403        return;
   3404
   3405    // Click to focus window and start moving (after we're done with all our widgets)
   3406    if (g.IO.MouseClicked[0])
   3407    {
   3408        if (g.HoveredRootWindow != NULL)
   3409        {
   3410            StartMouseMovingWindow(g.HoveredWindow);
   3411            if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar))
   3412                if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
   3413                    g.MovingWindow = NULL;
   3414        }
   3415        else if (g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
   3416        {
   3417            // Clicking on void disable focus
   3418            FocusWindow(NULL);
   3419        }
   3420    }
   3421
   3422    // With right mouse button we close popups without changing focus based on where the mouse is aimed
   3423    // Instead, focus will be restored to the window under the bottom-most closed popup.
   3424    // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
   3425    if (g.IO.MouseClicked[1])
   3426    {
   3427        // Find the top-most window between HoveredWindow and the top-most Modal Window.
   3428        // This is where we can trim the popup stack.
   3429        ImGuiWindow* modal = GetTopMostPopupModal();
   3430        bool hovered_window_above_modal = false;
   3431        if (modal == NULL)
   3432            hovered_window_above_modal = true;
   3433        for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
   3434        {
   3435            ImGuiWindow* window = g.Windows[i];
   3436            if (window == modal)
   3437                break;
   3438            if (window == g.HoveredWindow)
   3439                hovered_window_above_modal = true;
   3440        }
   3441        ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);
   3442    }
   3443}
   3444
   3445static bool IsWindowActiveAndVisible(ImGuiWindow* window)
   3446{
   3447    return (window->Active) && (!window->Hidden);
   3448}
   3449
   3450static void ImGui::UpdateMouseInputs()
   3451{
   3452    ImGuiContext& g = *GImGui;
   3453
   3454    // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
   3455    if (IsMousePosValid(&g.IO.MousePos))
   3456        g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos);
   3457
   3458    // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
   3459    if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
   3460        g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
   3461    else
   3462        g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
   3463    if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
   3464        g.NavDisableMouseHover = false;
   3465
   3466    g.IO.MousePosPrev = g.IO.MousePos;
   3467    for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
   3468    {
   3469        g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
   3470        g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
   3471        g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
   3472        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;
   3473        g.IO.MouseDoubleClicked[i] = false;
   3474        if (g.IO.MouseClicked[i])
   3475        {
   3476            if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime)
   3477            {
   3478                ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
   3479                if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
   3480                    g.IO.MouseDoubleClicked[i] = true;
   3481                g.IO.MouseClickedTime[i] = -DBL_MAX;    // so the third click isn't turned into a double-click
   3482            }
   3483            else
   3484            {
   3485                g.IO.MouseClickedTime[i] = g.Time;
   3486            }
   3487            g.IO.MouseClickedPos[i] = g.IO.MousePos;
   3488            g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i];
   3489            g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
   3490            g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
   3491        }
   3492        else if (g.IO.MouseDown[i])
   3493        {
   3494            // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold
   3495            ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
   3496            g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos));
   3497            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);
   3498            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);
   3499        }
   3500        if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i])
   3501            g.IO.MouseDownWasDoubleClick[i] = false;
   3502        if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
   3503            g.NavDisableMouseHover = false;
   3504    }
   3505}
   3506
   3507static void StartLockWheelingWindow(ImGuiWindow* window)
   3508{
   3509    ImGuiContext& g = *GImGui;
   3510    if (g.WheelingWindow == window)
   3511        return;
   3512    g.WheelingWindow = window;
   3513    g.WheelingWindowRefMousePos = g.IO.MousePos;
   3514    g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER;
   3515}
   3516
   3517void ImGui::UpdateMouseWheel()
   3518{
   3519    ImGuiContext& g = *GImGui;
   3520
   3521    // Reset the locked window if we move the mouse or after the timer elapses
   3522    if (g.WheelingWindow != NULL)
   3523    {
   3524        g.WheelingWindowTimer -= g.IO.DeltaTime;
   3525        if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)
   3526            g.WheelingWindowTimer = 0.0f;
   3527        if (g.WheelingWindowTimer <= 0.0f)
   3528        {
   3529            g.WheelingWindow = NULL;
   3530            g.WheelingWindowTimer = 0.0f;
   3531        }
   3532    }
   3533
   3534    if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
   3535        return;
   3536
   3537    ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
   3538    if (!window || window->Collapsed)
   3539        return;
   3540
   3541    // Zoom / Scale window
   3542    // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
   3543    if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
   3544    {
   3545        StartLockWheelingWindow(window);
   3546        const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
   3547        const float scale = new_font_scale / window->FontWindowScale;
   3548        window->FontWindowScale = new_font_scale;
   3549        if (!(window->Flags & ImGuiWindowFlags_ChildWindow))
   3550        {
   3551            const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
   3552            SetWindowPos(window, window->Pos + offset, 0);
   3553            window->Size = ImFloor(window->Size * scale);
   3554            window->SizeFull = ImFloor(window->SizeFull * scale);
   3555        }
   3556        return;
   3557    }
   3558
   3559    // Mouse wheel scrolling
   3560    // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent
   3561
   3562    // Vertical Mouse Wheel scrolling
   3563    const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
   3564    if (wheel_y != 0.0f && !g.IO.KeyCtrl)
   3565    {
   3566        StartLockWheelingWindow(window);
   3567        while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
   3568            window = window->ParentWindow;
   3569        if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
   3570        {
   3571            float max_step = window->InnerRect.GetHeight() * 0.67f;
   3572            float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
   3573            SetScrollY(window, window->Scroll.y - wheel_y * scroll_step);
   3574        }
   3575    }
   3576
   3577    // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
   3578    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;
   3579    if (wheel_x != 0.0f && !g.IO.KeyCtrl)
   3580    {
   3581        StartLockWheelingWindow(window);
   3582        while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
   3583            window = window->ParentWindow;
   3584        if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
   3585        {
   3586            float max_step = window->InnerRect.GetWidth() * 0.67f;
   3587            float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
   3588            SetScrollX(window, window->Scroll.x - wheel_x * scroll_step);
   3589        }
   3590    }
   3591}
   3592
   3593void ImGui::UpdateTabFocus()
   3594{
   3595    ImGuiContext& g = *GImGui;
   3596
   3597    // Pressing TAB activate widget focus
   3598    g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
   3599    if (g.ActiveId == 0 && g.FocusTabPressed)
   3600    {
   3601        // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
   3602        // manipulate the Next fields even, even though they will be turned into Curr fields by the code below.
   3603        g.FocusRequestNextWindow = g.NavWindow;
   3604        g.FocusRequestNextCounterRegular = INT_MAX;
   3605        if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
   3606            g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
   3607        else
   3608            g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
   3609    }
   3610
   3611    // Turn queued focus request into current one
   3612    g.FocusRequestCurrWindow = NULL;
   3613    g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX;
   3614    if (g.FocusRequestNextWindow != NULL)
   3615    {
   3616        ImGuiWindow* window = g.FocusRequestNextWindow;
   3617        g.FocusRequestCurrWindow = window;
   3618        if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1)
   3619            g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1);
   3620        if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1)
   3621            g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1);
   3622        g.FocusRequestNextWindow = NULL;
   3623        g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX;
   3624    }
   3625
   3626    g.NavIdTabCounter = INT_MAX;
   3627}
   3628
   3629// 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)
   3630void ImGui::UpdateHoveredWindowAndCaptureFlags()
   3631{
   3632    ImGuiContext& g = *GImGui;
   3633
   3634    // Find the window hovered by mouse:
   3635    // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
   3636    // - 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.
   3637    // - 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.
   3638    FindHoveredWindow();
   3639
   3640    // Modal windows prevents cursor from hovering behind them.
   3641    ImGuiWindow* modal_window = GetTopMostPopupModal();
   3642    if (modal_window)
   3643        if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
   3644            g.HoveredRootWindow = g.HoveredWindow = NULL;
   3645
   3646    // Disabled mouse?
   3647    if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
   3648        g.HoveredWindow = g.HoveredRootWindow = NULL;
   3649
   3650    // 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.
   3651    int mouse_earliest_button_down = -1;
   3652    bool mouse_any_down = false;
   3653    for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
   3654    {
   3655        if (g.IO.MouseClicked[i])
   3656            g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty());
   3657        mouse_any_down |= g.IO.MouseDown[i];
   3658        if (g.IO.MouseDown[i])
   3659            if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
   3660                mouse_earliest_button_down = i;
   3661    }
   3662    const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
   3663
   3664    // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
   3665    // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
   3666    const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
   3667    if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
   3668        g.HoveredWindow = g.HoveredRootWindow = NULL;
   3669
   3670    // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app)
   3671    if (g.WantCaptureMouseNextFrame != -1)
   3672        g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
   3673    else
   3674        g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
   3675
   3676    // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app)
   3677    if (g.WantCaptureKeyboardNextFrame != -1)
   3678        g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
   3679    else
   3680        g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
   3681    if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
   3682        g.IO.WantCaptureKeyboard = true;
   3683
   3684    // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
   3685    g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
   3686}
   3687
   3688ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
   3689{
   3690    ImGuiContext& g = *GImGui;
   3691    ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None;
   3692    if (g.IO.KeyCtrl)   { key_mod_flags |= ImGuiKeyModFlags_Ctrl; }
   3693    if (g.IO.KeyShift)  { key_mod_flags |= ImGuiKeyModFlags_Shift; }
   3694    if (g.IO.KeyAlt)    { key_mod_flags |= ImGuiKeyModFlags_Alt; }
   3695    if (g.IO.KeySuper)  { key_mod_flags |= ImGuiKeyModFlags_Super; }
   3696    return key_mod_flags;
   3697}
   3698
   3699void ImGui::NewFrame()
   3700{
   3701    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
   3702    ImGuiContext& g = *GImGui;
   3703
   3704#ifdef IMGUI_ENABLE_TEST_ENGINE
   3705    ImGuiTestEngineHook_PreNewFrame(&g);
   3706#endif
   3707
   3708    // Check and assert for various common IO and Configuration mistakes
   3709    ErrorCheckNewFrameSanityChecks();
   3710
   3711    // Load settings on first frame, save settings when modified (after a delay)
   3712    UpdateSettings();
   3713
   3714    g.Time += g.IO.DeltaTime;
   3715    g.WithinFrameScope = true;
   3716    g.FrameCount += 1;
   3717    g.TooltipOverrideCount = 0;
   3718    g.WindowsActiveCount = 0;
   3719    g.MenusIdSubmittedThisFrame.resize(0);
   3720
   3721    // Calculate frame-rate for the user, as a purely luxurious feature
   3722    g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
   3723    g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
   3724    g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
   3725    g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
   3726
   3727    // Setup current font and draw list shared data
   3728    g.IO.Fonts->Locked = true;
   3729    SetCurrentFont(GetDefaultFont());
   3730    IM_ASSERT(g.Font->IsLoaded());
   3731    g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
   3732    g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
   3733    g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError);
   3734    g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
   3735    if (g.Style.AntiAliasedLines)
   3736        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
   3737    if (g.Style.AntiAliasedFill)
   3738        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
   3739    if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
   3740        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
   3741
   3742    g.BackgroundDrawList.Clear();
   3743    g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID);
   3744    g.BackgroundDrawList.PushClipRectFullScreen();
   3745
   3746    g.ForegroundDrawList.Clear();
   3747    g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID);
   3748    g.ForegroundDrawList.PushClipRectFullScreen();
   3749
   3750    // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
   3751    g.DrawData.Clear();
   3752
   3753    // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
   3754    if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
   3755        KeepAliveID(g.DragDropPayload.SourceId);
   3756
   3757    // Update HoveredId data
   3758    if (!g.HoveredIdPreviousFrame)
   3759        g.HoveredIdTimer = 0.0f;
   3760    if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
   3761        g.HoveredIdNotActiveTimer = 0.0f;
   3762    if (g.HoveredId)
   3763        g.HoveredIdTimer += g.IO.DeltaTime;
   3764    if (g.HoveredId && g.ActiveId != g.HoveredId)
   3765        g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
   3766    g.HoveredIdPreviousFrame = g.HoveredId;
   3767    g.HoveredId = 0;
   3768    g.HoveredIdAllowOverlap = false;
   3769
   3770    // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
   3771    if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
   3772        ClearActiveID();
   3773    if (g.ActiveId)
   3774        g.ActiveIdTimer += g.IO.DeltaTime;
   3775    g.LastActiveIdTimer += g.IO.DeltaTime;
   3776    g.ActiveIdPreviousFrame = g.ActiveId;
   3777    g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
   3778    g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
   3779    g.ActiveIdIsAlive = 0;
   3780    g.ActiveIdHasBeenEditedThisFrame = false;
   3781    g.ActiveIdPreviousFrameIsAlive = false;
   3782    g.ActiveIdIsJustActivated = false;
   3783    if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
   3784        g.TempInputId = 0;
   3785    if (g.ActiveId == 0)
   3786    {
   3787        g.ActiveIdUsingNavDirMask = 0x00;
   3788        g.ActiveIdUsingNavInputMask = 0x00;
   3789        g.ActiveIdUsingKeyInputMask = 0x00;
   3790    }
   3791
   3792    // Drag and drop
   3793    g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
   3794    g.DragDropAcceptIdCurr = 0;
   3795    g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
   3796    g.DragDropWithinSource = false;
   3797    g.DragDropWithinTarget = false;
   3798
   3799    // Update keyboard input state
   3800    // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools
   3801    g.IO.KeyMods = GetMergedKeyModFlags();
   3802    memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
   3803    for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
   3804        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;
   3805
   3806    // Update gamepad/keyboard navigation
   3807    NavUpdate();
   3808
   3809    // Update mouse input state
   3810    UpdateMouseInputs();
   3811
   3812    // Find hovered window
   3813    // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
   3814    UpdateHoveredWindowAndCaptureFlags();
   3815
   3816    // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
   3817    UpdateMouseMovingWindowNewFrame();
   3818
   3819    // Background darkening/whitening
   3820    if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
   3821        g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
   3822    else
   3823        g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
   3824
   3825    g.MouseCursor = ImGuiMouseCursor_Arrow;
   3826    g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
   3827    g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
   3828
   3829    // Mouse wheel scrolling, scale
   3830    UpdateMouseWheel();
   3831
   3832    // Update legacy TAB focus
   3833    UpdateTabFocus();
   3834
   3835    // Mark all windows as not visible and compact unused memory.
   3836    IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
   3837    const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX;
   3838    for (int i = 0; i != g.Windows.Size; i++)
   3839    {
   3840        ImGuiWindow* window = g.Windows[i];
   3841        window->WasActive = window->Active;
   3842        window->BeginCount = 0;
   3843        window->Active = false;
   3844        window->WriteAccessed = false;
   3845
   3846        // Garbage collect transient buffers of recently unused windows
   3847        if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
   3848            GcCompactTransientWindowBuffers(window);
   3849    }
   3850
   3851    // Closing the focused window restore focus to the first active root window in descending z-order
   3852    if (g.NavWindow && !g.NavWindow->WasActive)
   3853        FocusTopMostWindowUnderOne(NULL, NULL);
   3854
   3855    // No window should be open at the beginning of the frame.
   3856    // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
   3857    g.CurrentWindowStack.resize(0);
   3858    g.BeginPopupStack.resize(0);
   3859    ClosePopupsOverWindow(g.NavWindow, false);
   3860
   3861    // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
   3862    UpdateDebugToolItemPicker();
   3863
   3864    // Create implicit/fallback window - which we will only render it if the user has added something to it.
   3865    // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
   3866    // This fallback is particularly important as it avoid ImGui:: calls from crashing.
   3867    g.WithinFrameScopeWithImplicitWindow = true;
   3868    SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver);
   3869    Begin("Debug##Default");
   3870    IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true);
   3871
   3872#ifdef IMGUI_ENABLE_TEST_ENGINE
   3873    ImGuiTestEngineHook_PostNewFrame(&g);
   3874#endif
   3875}
   3876
   3877// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
   3878void ImGui::UpdateDebugToolItemPicker()
   3879{
   3880    ImGuiContext& g = *GImGui;
   3881    g.DebugItemPickerBreakId = 0;
   3882    if (g.DebugItemPickerActive)
   3883    {
   3884        const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
   3885        ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
   3886        if (ImGui::IsKeyPressedMap(ImGuiKey_Escape))
   3887            g.DebugItemPickerActive = false;
   3888        if (ImGui::IsMouseClicked(0) && hovered_id)
   3889        {
   3890            g.DebugItemPickerBreakId = hovered_id;
   3891            g.DebugItemPickerActive = false;
   3892        }
   3893        ImGui::SetNextWindowBgAlpha(0.60f);
   3894        ImGui::BeginTooltip();
   3895        ImGui::Text("HoveredId: 0x%08X", hovered_id);
   3896        ImGui::Text("Press ESC to abort picking.");
   3897        ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
   3898        ImGui::EndTooltip();
   3899    }
   3900}
   3901
   3902void ImGui::Initialize(ImGuiContext* context)
   3903{
   3904    ImGuiContext& g = *context;
   3905    IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
   3906
   3907    // Add .ini handle for ImGuiWindow type
   3908    {
   3909        ImGuiSettingsHandler ini_handler;
   3910        ini_handler.TypeName = "Window";
   3911        ini_handler.TypeHash = ImHashStr("Window");
   3912        ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
   3913        ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
   3914        ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
   3915        g.SettingsHandlers.push_back(ini_handler);
   3916    }
   3917
   3918#ifdef IMGUI_HAS_TABLE
   3919    // Add .ini handle for ImGuiTable type
   3920    {
   3921        ImGuiSettingsHandler ini_handler;
   3922        ini_handler.TypeName = "Table";
   3923        ini_handler.TypeHash = ImHashStr("Table");
   3924        ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen;
   3925        ini_handler.ReadLineFn = TableSettingsHandler_ReadLine;
   3926        ini_handler.WriteAllFn = TableSettingsHandler_WriteAll;
   3927        g.SettingsHandlers.push_back(ini_handler);
   3928    }
   3929#endif // #ifdef IMGUI_HAS_TABLE
   3930
   3931#ifdef IMGUI_HAS_DOCK
   3932#endif // #ifdef IMGUI_HAS_DOCK
   3933
   3934    g.Initialized = true;
   3935}
   3936
   3937// This function is merely here to free heap allocations.
   3938void ImGui::Shutdown(ImGuiContext* context)
   3939{
   3940    // 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)
   3941    ImGuiContext& g = *context;
   3942    if (g.IO.Fonts && g.FontAtlasOwnedByContext)
   3943    {
   3944        g.IO.Fonts->Locked = false;
   3945        IM_DELETE(g.IO.Fonts);
   3946    }
   3947    g.IO.Fonts = NULL;
   3948
   3949    // Cleanup of other data are conditional on actually having initialized Dear ImGui.
   3950    if (!g.Initialized)
   3951        return;
   3952
   3953    // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
   3954    if (g.SettingsLoaded && g.IO.IniFilename != NULL)
   3955    {
   3956        ImGuiContext* backup_context = GImGui;
   3957        SetCurrentContext(context);
   3958        SaveIniSettingsToDisk(g.IO.IniFilename);
   3959        SetCurrentContext(backup_context);
   3960    }
   3961
   3962    // Clear everything else
   3963    for (int i = 0; i < g.Windows.Size; i++)
   3964        IM_DELETE(g.Windows[i]);
   3965    g.Windows.clear();
   3966    g.WindowsFocusOrder.clear();
   3967    g.WindowsTempSortBuffer.clear();
   3968    g.CurrentWindow = NULL;
   3969    g.CurrentWindowStack.clear();
   3970    g.WindowsById.Clear();
   3971    g.NavWindow = NULL;
   3972    g.HoveredWindow = g.HoveredRootWindow = NULL;
   3973    g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;
   3974    g.MovingWindow = NULL;
   3975    g.ColorModifiers.clear();
   3976    g.StyleModifiers.clear();
   3977    g.FontStack.clear();
   3978    g.OpenPopupStack.clear();
   3979    g.BeginPopupStack.clear();
   3980    g.DrawDataBuilder.ClearFreeMemory();
   3981    g.BackgroundDrawList.ClearFreeMemory();
   3982    g.ForegroundDrawList.ClearFreeMemory();
   3983
   3984    g.TabBars.Clear();
   3985    g.CurrentTabBarStack.clear();
   3986    g.ShrinkWidthBuffer.clear();
   3987
   3988    g.ClipboardHandlerData.clear();
   3989    g.MenusIdSubmittedThisFrame.clear();
   3990    g.InputTextState.ClearFreeMemory();
   3991
   3992    g.SettingsWindows.clear();
   3993    g.SettingsHandlers.clear();
   3994
   3995    if (g.LogFile)
   3996    {
   3997#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
   3998        if (g.LogFile != stdout)
   3999#endif
   4000            ImFileClose(g.LogFile);
   4001        g.LogFile = NULL;
   4002    }
   4003    g.LogBuffer.clear();
   4004
   4005    g.Initialized = false;
   4006}
   4007
   4008// FIXME: Add a more explicit sort order in the window structure.
   4009static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
   4010{
   4011    const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
   4012    const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
   4013    if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
   4014        return d;
   4015    if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
   4016        return d;
   4017    return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
   4018}
   4019
   4020static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
   4021{
   4022    out_sorted_windows->push_back(window);
   4023    if (window->Active)
   4024    {
   4025        int count = window->DC.ChildWindows.Size;
   4026        if (count > 1)
   4027            ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
   4028        for (int i = 0; i < count; i++)
   4029        {
   4030            ImGuiWindow* child = window->DC.ChildWindows[i];
   4031            if (child->Active)
   4032                AddWindowToSortBuffer(out_sorted_windows, child);
   4033        }
   4034    }
   4035}
   4036
   4037static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
   4038{
   4039    if (draw_list->CmdBuffer.empty())
   4040        return;
   4041
   4042    // Remove trailing command if unused
   4043    ImDrawCmd& last_cmd = draw_list->CmdBuffer.back();
   4044    if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL)
   4045    {
   4046        draw_list->CmdBuffer.pop_back();
   4047        if (draw_list->CmdBuffer.empty())
   4048            return;
   4049    }
   4050
   4051    // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
   4052    // May trigger for you if you are using PrimXXX functions incorrectly.
   4053    IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
   4054    IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
   4055    if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
   4056        IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
   4057
   4058    // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
   4059    // If this assert triggers because you are drawing lots of stuff manually:
   4060    // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
   4061    //   Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents.
   4062    // - If you want large meshes with more than 64K vertices, you can either:
   4063    //   (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
   4064    //       Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't.
   4065    //       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.
   4066    //   (B) Or handle 32-bit indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
   4067    //       Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time:
   4068    //         glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
   4069    //       Your own engine or render API may use different parameters or function calls to specify index sizes.
   4070    //       2 and 4 bytes indices are generally supported by most graphics API.
   4071    // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
   4072    //   the 64K limit to split your draw commands in multiple draw lists.
   4073    if (sizeof(ImDrawIdx) == 2)
   4074        IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
   4075
   4076    out_list->push_back(draw_list);
   4077}
   4078
   4079static void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window)
   4080{
   4081    ImGuiContext& g = *GImGui;
   4082    g.IO.MetricsRenderWindows++;
   4083    AddDrawListToDrawData(out_render_list, window->DrawList);
   4084    for (int i = 0; i < window->DC.ChildWindows.Size; i++)
   4085    {
   4086        ImGuiWindow* child = window->DC.ChildWindows[i];
   4087        if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active
   4088            AddWindowToDrawData(out_render_list, child);
   4089    }
   4090}
   4091
   4092// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu)
   4093static void AddRootWindowToDrawData(ImGuiWindow* window)
   4094{
   4095    ImGuiContext& g = *GImGui;
   4096    int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;
   4097    AddWindowToDrawData(&g.DrawDataBuilder.Layers[layer], window);
   4098}
   4099
   4100void ImDrawDataBuilder::FlattenIntoSingleLayer()
   4101{
   4102    int n = Layers[0].Size;
   4103    int size = n;
   4104    for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
   4105        size += Layers[i].Size;
   4106    Layers[0].resize(size);
   4107    for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
   4108    {
   4109        ImVector<ImDrawList*>& layer = Layers[layer_n];
   4110        if (layer.empty())
   4111            continue;
   4112        memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
   4113        n += layer.Size;
   4114        layer.resize(0);
   4115    }
   4116}
   4117
   4118static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* draw_data)
   4119{
   4120    ImGuiIO& io = ImGui::GetIO();
   4121    draw_data->Valid = true;
   4122    draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
   4123    draw_data->CmdListsCount = draw_lists->Size;
   4124    draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
   4125    draw_data->DisplayPos = ImVec2(0.0f, 0.0f);
   4126    draw_data->DisplaySize = io.DisplaySize;
   4127    draw_data->FramebufferScale = io.DisplayFramebufferScale;
   4128    for (int n = 0; n < draw_lists->Size; n++)
   4129    {
   4130        draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
   4131        draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
   4132    }
   4133}
   4134
   4135// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result.
   4136void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
   4137{
   4138    ImGuiWindow* window = GetCurrentWindow();
   4139    window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
   4140    window->ClipRect = window->DrawList->_ClipRectStack.back();
   4141}
   4142
   4143void ImGui::PopClipRect()
   4144{
   4145    ImGuiWindow* window = GetCurrentWindow();
   4146    window->DrawList->PopClipRect();
   4147    window->ClipRect = window->DrawList->_ClipRectStack.back();
   4148}
   4149
   4150// 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.
   4151void ImGui::EndFrame()
   4152{
   4153    ImGuiContext& g = *GImGui;
   4154    IM_ASSERT(g.Initialized);
   4155
   4156    // Don't process EndFrame() multiple times.
   4157    if (g.FrameCountEnded == g.FrameCount)
   4158        return;
   4159    IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
   4160
   4161    ErrorCheckEndFrameSanityChecks();
   4162
   4163    // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
   4164    if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f))
   4165    {
   4166        g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y);
   4167        g.PlatformImeLastPos = g.PlatformImePos;
   4168    }
   4169
   4170    // Hide implicit/fallback "Debug" window if it hasn't been used
   4171    g.WithinFrameScopeWithImplicitWindow = false;
   4172    if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
   4173        g.CurrentWindow->Active = false;
   4174    End();
   4175
   4176    // Show CTRL+TAB list window
   4177    if (g.NavWindowingTarget != NULL)
   4178        NavUpdateWindowingOverlay();
   4179
   4180    // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
   4181    if (g.DragDropActive)
   4182    {
   4183        bool is_delivered = g.DragDropPayload.Delivery;
   4184        bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));
   4185        if (is_delivered || is_elapsed)
   4186            ClearDragDrop();
   4187    }
   4188
   4189    // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.
   4190    if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount)
   4191    {
   4192        g.DragDropWithinSource = true;
   4193        SetTooltip("...");
   4194        g.DragDropWithinSource = false;
   4195    }
   4196
   4197    // End frame
   4198    g.WithinFrameScope = false;
   4199    g.FrameCountEnded = g.FrameCount;
   4200
   4201    // Initiate moving window + handle left-click and right-click focus
   4202    UpdateMouseMovingWindowEndFrame();
   4203
   4204    // Sort the window list so that all child windows are after their parent
   4205    // We cannot do that on FocusWindow() because childs may not exist yet
   4206    g.WindowsTempSortBuffer.resize(0);
   4207    g.WindowsTempSortBuffer.reserve(g.Windows.Size);
   4208    for (int i = 0; i != g.Windows.Size; i++)
   4209    {
   4210        ImGuiWindow* window = g.Windows[i];
   4211        if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow))       // if a child is active its parent will add it
   4212            continue;
   4213        AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);
   4214    }
   4215
   4216    // 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.
   4217    IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size);
   4218    g.Windows.swap(g.WindowsTempSortBuffer);
   4219    g.IO.MetricsActiveWindows = g.WindowsActiveCount;
   4220
   4221    // Unlock font atlas
   4222    g.IO.Fonts->Locked = false;
   4223
   4224    // Clear Input data for next frame
   4225    g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
   4226    g.IO.InputQueueCharacters.resize(0);
   4227    memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
   4228}
   4229
   4230void ImGui::Render()
   4231{
   4232    ImGuiContext& g = *GImGui;
   4233    IM_ASSERT(g.Initialized);
   4234
   4235    if (g.FrameCountEnded != g.FrameCount)
   4236        EndFrame();
   4237    g.FrameCountRendered = g.FrameCount;
   4238    g.IO.MetricsRenderWindows = 0;
   4239    g.DrawDataBuilder.Clear();
   4240
   4241    // Add background ImDrawList
   4242    if (!g.BackgroundDrawList.VtxBuffer.empty())
   4243        AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList);
   4244
   4245    // Add ImDrawList to render
   4246    ImGuiWindow* windows_to_render_top_most[2];
   4247    windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
   4248    windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingList : NULL);
   4249    for (int n = 0; n != g.Windows.Size; n++)
   4250    {
   4251        ImGuiWindow* window = g.Windows[n];
   4252        if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
   4253            AddRootWindowToDrawData(window);
   4254    }
   4255    for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
   4256        if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
   4257            AddRootWindowToDrawData(windows_to_render_top_most[n]);
   4258    g.DrawDataBuilder.FlattenIntoSingleLayer();
   4259
   4260    // Draw software mouse cursor if requested
   4261    if (g.IO.MouseDrawCursor)
   4262        RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
   4263
   4264    // Add foreground ImDrawList
   4265    if (!g.ForegroundDrawList.VtxBuffer.empty())
   4266        AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList);
   4267
   4268    // Setup ImDrawData structure for end-user
   4269    SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData);
   4270    g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount;
   4271    g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount;
   4272
   4273    // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves.
   4274#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
   4275    if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
   4276        g.IO.RenderDrawListsFn(&g.DrawData);
   4277#endif
   4278}
   4279
   4280// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
   4281// CalcTextSize("") should return ImVec2(0.0f, g.FontSize)
   4282ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
   4283{
   4284    ImGuiContext& g = *GImGui;
   4285
   4286    const char* text_display_end;
   4287    if (hide_text_after_double_hash)
   4288        text_display_end = FindRenderedTextEnd(text, text_end);      // Hide anything after a '##' string
   4289    else
   4290        text_display_end = text_end;
   4291
   4292    ImFont* font = g.Font;
   4293    const float font_size = g.FontSize;
   4294    if (text == text_display_end)
   4295        return ImVec2(0.0f, font_size);
   4296    ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
   4297
   4298    // Round
   4299    text_size.x = IM_FLOOR(text_size.x + 0.95f);
   4300
   4301    return text_size;
   4302}
   4303
   4304// Find window given position, search front-to-back
   4305// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically
   4306// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
   4307// called, aka before the next Begin(). Moving window isn't affected.
   4308static void FindHoveredWindow()
   4309{
   4310    ImGuiContext& g = *GImGui;
   4311
   4312    ImGuiWindow* hovered_window = NULL;
   4313    if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs))
   4314        hovered_window = g.MovingWindow;
   4315
   4316    ImVec2 padding_regular = g.Style.TouchExtraPadding;
   4317    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;
   4318    for (int i = g.Windows.Size - 1; i >= 0; i--)
   4319    {
   4320        ImGuiWindow* window = g.Windows[i];
   4321        if (!window->Active || window->Hidden)
   4322            continue;
   4323        if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
   4324            continue;
   4325
   4326        // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
   4327        ImRect bb(window->OuterRectClipped);
   4328        if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
   4329            bb.Expand(padding_regular);
   4330        else
   4331            bb.Expand(padding_for_resize_from_edges);
   4332        if (!bb.Contains(g.IO.MousePos))
   4333            continue;
   4334
   4335        // Those seemingly unnecessary extra tests are because the code here is a little different in viewport/docking branches.
   4336        if (hovered_window == NULL)
   4337            hovered_window = window;
   4338        if (hovered_window)
   4339            break;
   4340    }
   4341
   4342    g.HoveredWindow = hovered_window;
   4343    g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
   4344
   4345}
   4346
   4347// Test if mouse cursor is hovering given rectangle
   4348// NB- Rectangle is clipped by our current clip setting
   4349// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
   4350bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
   4351{
   4352    ImGuiContext& g = *GImGui;
   4353
   4354    // Clip
   4355    ImRect rect_clipped(r_min, r_max);
   4356    if (clip)
   4357        rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
   4358
   4359    // Expand for touch input
   4360    const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
   4361    if (!rect_for_touch.Contains(g.IO.MousePos))
   4362        return false;
   4363    return true;
   4364}
   4365
   4366int ImGui::GetKeyIndex(ImGuiKey imgui_key)
   4367{
   4368    IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
   4369    ImGuiContext& g = *GImGui;
   4370    return g.IO.KeyMap[imgui_key];
   4371}
   4372
   4373// Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]!
   4374// Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]!
   4375bool ImGui::IsKeyDown(int user_key_index)
   4376{
   4377    if (user_key_index < 0)
   4378        return false;
   4379    ImGuiContext& g = *GImGui;
   4380    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
   4381    return g.IO.KeysDown[user_key_index];
   4382}
   4383
   4384// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
   4385// t1 = current time (e.g.: g.Time)
   4386// An event is triggered at:
   4387//  t = 0.0f     t = repeat_delay,    t = repeat_delay + repeat_rate*N
   4388int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
   4389{
   4390    if (t1 == 0.0f)
   4391        return 1;
   4392    if (t0 >= t1)
   4393        return 0;
   4394    if (repeat_rate <= 0.0f)
   4395        return (t0 < repeat_delay) && (t1 >= repeat_delay);
   4396    const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
   4397    const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
   4398    const int count = count_t1 - count_t0;
   4399    return count;
   4400}
   4401
   4402int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
   4403{
   4404    ImGuiContext& g = *GImGui;
   4405    if (key_index < 0)
   4406        return 0;
   4407    IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
   4408    const float t = g.IO.KeysDownDuration[key_index];
   4409    return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
   4410}
   4411
   4412bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
   4413{
   4414    ImGuiContext& g = *GImGui;
   4415    if (user_key_index < 0)
   4416        return false;
   4417    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
   4418    const float t = g.IO.KeysDownDuration[user_key_index];
   4419    if (t == 0.0f)
   4420        return true;
   4421    if (repeat && t > g.IO.KeyRepeatDelay)
   4422        return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
   4423    return false;
   4424}
   4425
   4426bool ImGui::IsKeyReleased(int user_key_index)
   4427{
   4428    ImGuiContext& g = *GImGui;
   4429    if (user_key_index < 0) return false;
   4430    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
   4431    return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
   4432}
   4433
   4434bool ImGui::IsMouseDown(ImGuiMouseButton button)
   4435{
   4436    ImGuiContext& g = *GImGui;
   4437    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4438    return g.IO.MouseDown[button];
   4439}
   4440
   4441bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
   4442{
   4443    ImGuiContext& g = *GImGui;
   4444    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4445    const float t = g.IO.MouseDownDuration[button];
   4446    if (t == 0.0f)
   4447        return true;
   4448
   4449    if (repeat && t > g.IO.KeyRepeatDelay)
   4450    {
   4451        // 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.
   4452        int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f);
   4453        if (amount > 0)
   4454            return true;
   4455    }
   4456    return false;
   4457}
   4458
   4459bool ImGui::IsMouseReleased(ImGuiMouseButton button)
   4460{
   4461    ImGuiContext& g = *GImGui;
   4462    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4463    return g.IO.MouseReleased[button];
   4464}
   4465
   4466bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
   4467{
   4468    ImGuiContext& g = *GImGui;
   4469    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4470    return g.IO.MouseDoubleClicked[button];
   4471}
   4472
   4473// [Internal] This doesn't test if the button is pressed
   4474bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold)
   4475{
   4476    ImGuiContext& g = *GImGui;
   4477    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4478    if (lock_threshold < 0.0f)
   4479        lock_threshold = g.IO.MouseDragThreshold;
   4480    return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
   4481}
   4482
   4483bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
   4484{
   4485    ImGuiContext& g = *GImGui;
   4486    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4487    if (!g.IO.MouseDown[button])
   4488        return false;
   4489    return IsMouseDragPastThreshold(button, lock_threshold);
   4490}
   4491
   4492ImVec2 ImGui::GetMousePos()
   4493{
   4494    ImGuiContext& g = *GImGui;
   4495    return g.IO.MousePos;
   4496}
   4497
   4498// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
   4499ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
   4500{
   4501    ImGuiContext& g = *GImGui;
   4502    if (g.BeginPopupStack.Size > 0)
   4503        return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos;
   4504    return g.IO.MousePos;
   4505}
   4506
   4507// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
   4508bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
   4509{
   4510    // The assert is only to silence a false-positive in XCode Static Analysis.
   4511    // 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).
   4512    IM_ASSERT(GImGui != NULL);
   4513    const float MOUSE_INVALID = -256000.0f;
   4514    ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
   4515    return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
   4516}
   4517
   4518bool ImGui::IsAnyMouseDown()
   4519{
   4520    ImGuiContext& g = *GImGui;
   4521    for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
   4522        if (g.IO.MouseDown[n])
   4523            return true;
   4524    return false;
   4525}
   4526
   4527// Return the delta from the initial clicking position while the mouse button is clicked or was just released.
   4528// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
   4529// NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window.
   4530ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold)
   4531{
   4532    ImGuiContext& g = *GImGui;
   4533    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4534    if (lock_threshold < 0.0f)
   4535        lock_threshold = g.IO.MouseDragThreshold;
   4536    if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
   4537        if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
   4538            if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button]))
   4539                return g.IO.MousePos - g.IO.MouseClickedPos[button];
   4540    return ImVec2(0.0f, 0.0f);
   4541}
   4542
   4543void ImGui::ResetMouseDragDelta(ImGuiMouseButton button)
   4544{
   4545    ImGuiContext& g = *GImGui;
   4546    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4547    // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
   4548    g.IO.MouseClickedPos[button] = g.IO.MousePos;
   4549}
   4550
   4551ImGuiMouseCursor ImGui::GetMouseCursor()
   4552{
   4553    return GImGui->MouseCursor;
   4554}
   4555
   4556void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
   4557{
   4558    GImGui->MouseCursor = cursor_type;
   4559}
   4560
   4561void ImGui::CaptureKeyboardFromApp(bool capture)
   4562{
   4563    GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
   4564}
   4565
   4566void ImGui::CaptureMouseFromApp(bool capture)
   4567{
   4568    GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
   4569}
   4570
   4571bool ImGui::IsItemActive()
   4572{
   4573    ImGuiContext& g = *GImGui;
   4574    if (g.ActiveId)
   4575    {
   4576        ImGuiWindow* window = g.CurrentWindow;
   4577        return g.ActiveId == window->DC.LastItemId;
   4578    }
   4579    return false;
   4580}
   4581
   4582bool ImGui::IsItemActivated()
   4583{
   4584    ImGuiContext& g = *GImGui;
   4585    if (g.ActiveId)
   4586    {
   4587        ImGuiWindow* window = g.CurrentWindow;
   4588        if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
   4589            return true;
   4590    }
   4591    return false;
   4592}
   4593
   4594bool ImGui::IsItemDeactivated()
   4595{
   4596    ImGuiContext& g = *GImGui;
   4597    ImGuiWindow* window = g.CurrentWindow;
   4598    if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
   4599        return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
   4600    return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
   4601}
   4602
   4603bool ImGui::IsItemDeactivatedAfterEdit()
   4604{
   4605    ImGuiContext& g = *GImGui;
   4606    return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));
   4607}
   4608
   4609bool ImGui::IsItemFocused()
   4610{
   4611    ImGuiContext& g = *GImGui;
   4612    ImGuiWindow* window = g.CurrentWindow;
   4613
   4614    if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId)
   4615        return false;
   4616    return true;
   4617}
   4618
   4619bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)
   4620{
   4621    return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
   4622}
   4623
   4624bool ImGui::IsItemToggledOpen()
   4625{
   4626    ImGuiContext& g = *GImGui;
   4627    return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
   4628}
   4629
   4630bool ImGui::IsItemToggledSelection()
   4631{
   4632    ImGuiContext& g = *GImGui;
   4633    return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
   4634}
   4635
   4636bool ImGui::IsAnyItemHovered()
   4637{
   4638    ImGuiContext& g = *GImGui;
   4639    return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
   4640}
   4641
   4642bool ImGui::IsAnyItemActive()
   4643{
   4644    ImGuiContext& g = *GImGui;
   4645    return g.ActiveId != 0;
   4646}
   4647
   4648bool ImGui::IsAnyItemFocused()
   4649{
   4650    ImGuiContext& g = *GImGui;
   4651    return g.NavId != 0 && !g.NavDisableHighlight;
   4652}
   4653
   4654bool ImGui::IsItemVisible()
   4655{
   4656    ImGuiWindow* window = GetCurrentWindowRead();
   4657    return window->ClipRect.Overlaps(window->DC.LastItemRect);
   4658}
   4659
   4660bool ImGui::IsItemEdited()
   4661{
   4662    ImGuiWindow* window = GetCurrentWindowRead();
   4663    return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0;
   4664}
   4665
   4666// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
   4667void ImGui::SetItemAllowOverlap()
   4668{
   4669    ImGuiContext& g = *GImGui;
   4670    if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
   4671        g.HoveredIdAllowOverlap = true;
   4672    if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
   4673        g.ActiveIdAllowOverlap = true;
   4674}
   4675
   4676ImVec2 ImGui::GetItemRectMin()
   4677{
   4678    ImGuiWindow* window = GetCurrentWindowRead();
   4679    return window->DC.LastItemRect.Min;
   4680}
   4681
   4682ImVec2 ImGui::GetItemRectMax()
   4683{
   4684    ImGuiWindow* window = GetCurrentWindowRead();
   4685    return window->DC.LastItemRect.Max;
   4686}
   4687
   4688ImVec2 ImGui::GetItemRectSize()
   4689{
   4690    ImGuiWindow* window = GetCurrentWindowRead();
   4691    return window->DC.LastItemRect.GetSize();
   4692}
   4693
   4694static ImRect GetViewportRect()
   4695{
   4696    ImGuiContext& g = *GImGui;
   4697    return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
   4698}
   4699
   4700bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
   4701{
   4702    ImGuiContext& g = *GImGui;
   4703    ImGuiWindow* parent_window = g.CurrentWindow;
   4704
   4705    flags |= ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow;
   4706    flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove);  // Inherit the NoMove flag
   4707
   4708    // Size
   4709    const ImVec2 content_avail = GetContentRegionAvail();
   4710    ImVec2 size = ImFloor(size_arg);
   4711    const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
   4712    if (size.x <= 0.0f)
   4713        size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
   4714    if (size.y <= 0.0f)
   4715        size.y = ImMax(content_avail.y + size.y, 4.0f);
   4716    SetNextWindowSize(size);
   4717
   4718    // 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.
   4719    char title[256];
   4720    if (name)
   4721        ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id);
   4722    else
   4723        ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id);
   4724
   4725    const float backup_border_size = g.Style.ChildBorderSize;
   4726    if (!border)
   4727        g.Style.ChildBorderSize = 0.0f;
   4728    bool ret = Begin(title, NULL, flags);
   4729    g.Style.ChildBorderSize = backup_border_size;
   4730
   4731    ImGuiWindow* child_window = g.CurrentWindow;
   4732    child_window->ChildId = id;
   4733    child_window->AutoFitChildAxises = (ImS8)auto_fit_axises;
   4734
   4735    // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
   4736    // While this is not really documented/defined, it seems that the expected thing to do.
   4737    if (child_window->BeginCount == 1)
   4738        parent_window->DC.CursorPos = child_window->Pos;
   4739
   4740    // Process navigation-in immediately so NavInit can run on first frame
   4741    if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
   4742    {
   4743        FocusWindow(child_window);
   4744        NavInitWindow(child_window, false);
   4745        SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item
   4746        g.ActiveIdSource = ImGuiInputSource_Nav;
   4747    }
   4748    return ret;
   4749}
   4750
   4751bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
   4752{
   4753    ImGuiWindow* window = GetCurrentWindow();
   4754    return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
   4755}
   4756
   4757bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
   4758{
   4759    IM_ASSERT(id != 0);
   4760    return BeginChildEx(NULL, id, size_arg, border, extra_flags);
   4761}
   4762
   4763void ImGui::EndChild()
   4764{
   4765    ImGuiContext& g = *GImGui;
   4766    ImGuiWindow* window = g.CurrentWindow;
   4767
   4768    IM_ASSERT(g.WithinEndChild == false);
   4769    IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);   // Mismatched BeginChild()/EndChild() calls
   4770
   4771    g.WithinEndChild = true;
   4772    if (window->BeginCount > 1)
   4773    {
   4774        End();
   4775    }
   4776    else
   4777    {
   4778        ImVec2 sz = window->Size;
   4779        if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
   4780            sz.x = ImMax(4.0f, sz.x);
   4781        if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
   4782            sz.y = ImMax(4.0f, sz.y);
   4783        End();
   4784
   4785        ImGuiWindow* parent_window = g.CurrentWindow;
   4786        ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
   4787        ItemSize(sz);
   4788        if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
   4789        {
   4790            ItemAdd(bb, window->ChildId);
   4791            RenderNavHighlight(bb, window->ChildId);
   4792
   4793            // When browsing a window that has no activable items (scroll only) we keep a highlight on the child
   4794            if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
   4795                RenderNavHighlight(ImRect(bb.Min - ImVec2(2,2), bb.Max + ImVec2(2,2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
   4796        }
   4797        else
   4798        {
   4799            // Not navigable into
   4800            ItemAdd(bb, 0);
   4801        }
   4802    }
   4803    g.WithinEndChild = false;
   4804}
   4805
   4806// Helper to create a child window / scrolling region that looks like a normal widget frame.
   4807bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)
   4808{
   4809    ImGuiContext& g = *GImGui;
   4810    const ImGuiStyle& style = g.Style;
   4811    PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
   4812    PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
   4813    PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
   4814    PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
   4815    bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);
   4816    PopStyleVar(3);
   4817    PopStyleColor();
   4818    return ret;
   4819}
   4820
   4821void ImGui::EndChildFrame()
   4822{
   4823    EndChild();
   4824}
   4825
   4826static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
   4827{
   4828    window->SetWindowPosAllowFlags       = enabled ? (window->SetWindowPosAllowFlags       | flags) : (window->SetWindowPosAllowFlags       & ~flags);
   4829    window->SetWindowSizeAllowFlags      = enabled ? (window->SetWindowSizeAllowFlags      | flags) : (window->SetWindowSizeAllowFlags      & ~flags);
   4830    window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
   4831}
   4832
   4833ImGuiWindow* ImGui::FindWindowByID(ImGuiID id)
   4834{
   4835    ImGuiContext& g = *GImGui;
   4836    return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
   4837}
   4838
   4839ImGuiWindow* ImGui::FindWindowByName(const char* name)
   4840{
   4841    ImGuiID id = ImHashStr(name);
   4842    return FindWindowByID(id);
   4843}
   4844
   4845static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags)
   4846{
   4847    ImGuiContext& g = *GImGui;
   4848    //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
   4849
   4850    // Create window the first time
   4851    ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
   4852    window->Flags = flags;
   4853    g.WindowsById.SetVoidPtr(window->ID, window);
   4854
   4855    // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
   4856    window->Pos = ImVec2(60, 60);
   4857
   4858    // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
   4859    if (!(flags & ImGuiWindowFlags_NoSavedSettings))
   4860        if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
   4861        {
   4862            // Retrieve settings from .ini file
   4863            window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
   4864            SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
   4865            window->Pos = ImVec2(settings->Pos.x, settings->Pos.y);
   4866            window->Collapsed = settings->Collapsed;
   4867            if (settings->Size.x > 0 && settings->Size.y > 0)
   4868                size = ImVec2(settings->Size.x, settings->Size.y);
   4869        }
   4870    window->Size = window->SizeFull = ImFloor(size);
   4871    window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
   4872
   4873    if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
   4874    {
   4875        window->AutoFitFramesX = window->AutoFitFramesY = 2;
   4876        window->AutoFitOnlyGrows = false;
   4877    }
   4878    else
   4879    {
   4880        if (window->Size.x <= 0.0f)
   4881            window->AutoFitFramesX = 2;
   4882        if (window->Size.y <= 0.0f)
   4883            window->AutoFitFramesY = 2;
   4884        window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
   4885    }
   4886
   4887    g.WindowsFocusOrder.push_back(window);
   4888    if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
   4889        g.Windows.push_front(window); // Quite slow but rare and only once
   4890    else
   4891        g.Windows.push_back(window);
   4892    return window;
   4893}
   4894
   4895static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
   4896{
   4897    ImGuiContext& g = *GImGui;
   4898    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
   4899    {
   4900        // Using -1,-1 on either X/Y axis to preserve the current size.
   4901        ImRect cr = g.NextWindowData.SizeConstraintRect;
   4902        new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
   4903        new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
   4904        if (g.NextWindowData.SizeCallback)
   4905        {
   4906            ImGuiSizeCallbackData data;
   4907            data.UserData = g.NextWindowData.SizeCallbackUserData;
   4908            data.Pos = window->Pos;
   4909            data.CurrentSize = window->SizeFull;
   4910            data.DesiredSize = new_size;
   4911            g.NextWindowData.SizeCallback(&data);
   4912            new_size = data.DesiredSize;
   4913        }
   4914        new_size.x = IM_FLOOR(new_size.x);
   4915        new_size.y = IM_FLOOR(new_size.y);
   4916    }
   4917
   4918    // Minimum size
   4919    if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
   4920    {
   4921        ImGuiWindow* window_for_height = window;
   4922        new_size = ImMax(new_size, g.Style.WindowMinSize);
   4923        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
   4924    }
   4925    return new_size;
   4926}
   4927
   4928static ImVec2 CalcWindowContentSize(ImGuiWindow* window)
   4929{
   4930    if (window->Collapsed)
   4931        if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
   4932            return window->ContentSize;
   4933    if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
   4934        return window->ContentSize;
   4935
   4936    ImVec2 sz;
   4937    sz.x = IM_FLOOR((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
   4938    sz.y = IM_FLOOR((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
   4939    return sz;
   4940}
   4941
   4942static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)
   4943{
   4944    ImGuiContext& g = *GImGui;
   4945    ImGuiStyle& style = g.Style;
   4946    ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight());
   4947    ImVec2 size_pad = window->WindowPadding * 2.0f;
   4948    ImVec2 size_desired = size_contents + size_pad + size_decorations;
   4949    if (window->Flags & ImGuiWindowFlags_Tooltip)
   4950    {
   4951        // Tooltip always resize
   4952        return size_desired;
   4953    }
   4954    else
   4955    {
   4956        // Maximum window size is determined by the viewport size or monitor size
   4957        const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
   4958        const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
   4959        ImVec2 size_min = style.WindowMinSize;
   4960        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)
   4961            size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
   4962        ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
   4963
   4964        // When the window cannot fit all contents (either because of constraints, either because screen is too small),
   4965        // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
   4966        ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
   4967        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);
   4968        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);
   4969        if (will_have_scrollbar_x)
   4970            size_auto_fit.y += style.ScrollbarSize;
   4971        if (will_have_scrollbar_y)
   4972            size_auto_fit.x += style.ScrollbarSize;
   4973        return size_auto_fit;
   4974    }
   4975}
   4976
   4977ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window)
   4978{
   4979    ImVec2 size_contents = CalcWindowContentSize(window);
   4980    ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents);
   4981    ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);
   4982    return size_final;
   4983}
   4984
   4985static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
   4986{
   4987    if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
   4988        return ImGuiCol_PopupBg;
   4989    if (flags & ImGuiWindowFlags_ChildWindow)
   4990        return ImGuiCol_ChildBg;
   4991    return ImGuiCol_WindowBg;
   4992}
   4993
   4994static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
   4995{
   4996    ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm);                // Expected window upper-left
   4997    ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
   4998    ImVec2 size_expected = pos_max - pos_min;
   4999    ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);
   5000    *out_pos = pos_min;
   5001    if (corner_norm.x == 0.0f)
   5002        out_pos->x -= (size_constrained.x - size_expected.x);
   5003    if (corner_norm.y == 0.0f)
   5004        out_pos->y -= (size_constrained.y - size_expected.y);
   5005    *out_size = size_constrained;
   5006}
   5007
   5008struct ImGuiResizeGripDef
   5009{
   5010    ImVec2  CornerPosN;
   5011    ImVec2  InnerDir;
   5012    int     AngleMin12, AngleMax12;
   5013};
   5014
   5015static const ImGuiResizeGripDef resize_grip_def[4] =
   5016{
   5017    { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower-right
   5018    { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower-left
   5019    { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper-left (Unused)
   5020    { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper-right (Unused)
   5021};
   5022
   5023static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
   5024{
   5025    ImRect rect = window->Rect();
   5026    if (thickness == 0.0f) rect.Max -= ImVec2(1,1);
   5027    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
   5028    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
   5029    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
   5030    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
   5031    IM_ASSERT(0);
   5032    return ImRect();
   5033}
   5034
   5035// 0..3: corners (Lower-right, Lower-left, Unused, Unused)
   5036// 4..7: borders (Top, Right, Bottom, Left)
   5037ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n)
   5038{
   5039    IM_ASSERT(n >= 0 && n <= 7);
   5040    ImGuiID id = window->ID;
   5041    id = ImHashStr("#RESIZE", 0, id);
   5042    id = ImHashData(&n, sizeof(int), id);
   5043    return id;
   5044}
   5045
   5046// Handle resize for: Resize Grips, Borders, Gamepad
   5047// Return true when using auto-fit (double click on resize grip)
   5048static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
   5049{
   5050    ImGuiContext& g = *GImGui;
   5051    ImGuiWindowFlags flags = window->Flags;
   5052
   5053    if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
   5054        return false;
   5055    if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
   5056        return false;
   5057
   5058    bool ret_auto_fit = false;
   5059    const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
   5060    const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
   5061    const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);
   5062    const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f;
   5063
   5064    ImVec2 pos_target(FLT_MAX, FLT_MAX);
   5065    ImVec2 size_target(FLT_MAX, FLT_MAX);
   5066
   5067    // Resize grips and borders are on layer 1
   5068    window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
   5069    window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
   5070
   5071    // Manual resize grips
   5072    PushID("#RESIZE");
   5073    for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
   5074    {
   5075        const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
   5076        const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
   5077
   5078        // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
   5079        ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
   5080        if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
   5081        if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
   5082        bool hovered, held;
   5083        ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
   5084        //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
   5085        if (hovered || held)
   5086            g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
   5087
   5088        if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
   5089        {
   5090            // Manual auto-fit when double-clicking
   5091            size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
   5092            ret_auto_fit = true;
   5093            ClearActiveID();
   5094        }
   5095        else if (held)
   5096        {
   5097            // Resize from any of the four corners
   5098            // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
   5099            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
   5100            CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target);
   5101        }
   5102        if (resize_grip_n == 0 || held || hovered)
   5103            resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
   5104    }
   5105    for (int border_n = 0; border_n < resize_border_count; border_n++)
   5106    {
   5107        bool hovered, held;
   5108        ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS);
   5109        ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
   5110        //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
   5111        if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
   5112        {
   5113            g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
   5114            if (held)
   5115                *border_held = border_n;
   5116        }
   5117        if (held)
   5118        {
   5119            ImVec2 border_target = window->Pos;
   5120            ImVec2 border_posn;
   5121            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
   5122            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
   5123            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
   5124            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
   5125            CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
   5126        }
   5127    }
   5128    PopID();
   5129
   5130    // Restore nav layer
   5131    window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
   5132    window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
   5133
   5134    // Navigation resize (keyboard/gamepad)
   5135    if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window)
   5136    {
   5137        ImVec2 nav_resize_delta;
   5138        if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift)
   5139            nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
   5140        if (g.NavInputSource == ImGuiInputSource_NavGamepad)
   5141            nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down);
   5142        if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
   5143        {
   5144            const float NAV_RESIZE_SPEED = 600.0f;
   5145            nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
   5146            g.NavWindowingToggleLayer = false;
   5147            g.NavDisableMouseHover = true;
   5148            resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
   5149            // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
   5150            size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
   5151        }
   5152    }
   5153
   5154    // Apply back modified position/size to window
   5155    if (size_target.x != FLT_MAX)
   5156    {
   5157        window->SizeFull = size_target;
   5158        MarkIniSettingsDirty(window);
   5159    }
   5160    if (pos_target.x != FLT_MAX)
   5161    {
   5162        window->Pos = ImFloor(pos_target);
   5163        MarkIniSettingsDirty(window);
   5164    }
   5165
   5166    window->Size = window->SizeFull;
   5167    return ret_auto_fit;
   5168}
   5169
   5170static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, const ImVec2& padding)
   5171{
   5172    ImGuiContext& g = *GImGui;
   5173    ImVec2 size_for_clamping = (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) ? ImVec2(window->Size.x, window->TitleBarHeight()) : window->Size;
   5174    window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + size_for_clamping, rect.Min + padding) - size_for_clamping);
   5175}
   5176
   5177static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
   5178{
   5179    ImGuiContext& g = *GImGui;
   5180    float rounding = window->WindowRounding;
   5181    float border_size = window->WindowBorderSize;
   5182    if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))
   5183        window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
   5184
   5185    int border_held = window->ResizeBorderHeld;
   5186    if (border_held != -1)
   5187    {
   5188        struct ImGuiResizeBorderDef
   5189        {
   5190            ImVec2 InnerDir;
   5191            ImVec2 CornerPosN1, CornerPosN2;
   5192            float  OuterAngle;
   5193        };
   5194        static const ImGuiResizeBorderDef resize_border_def[4] =
   5195        {
   5196            { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top
   5197            { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right
   5198            { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom
   5199            { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f }  // Left
   5200        };
   5201        const ImGuiResizeBorderDef& def = resize_border_def[border_held];
   5202        ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
   5203        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);
   5204        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);
   5205        window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual
   5206    }
   5207    if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
   5208    {
   5209        float y = window->Pos.y + window->TitleBarHeight() - 1;
   5210        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);
   5211    }
   5212}
   5213
   5214// Draw background and borders
   5215// Draw and handle scrollbars
   5216void 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)
   5217{
   5218    ImGuiContext& g = *GImGui;
   5219    ImGuiStyle& style = g.Style;
   5220    ImGuiWindowFlags flags = window->Flags;
   5221
   5222    // Ensure that ScrollBar doesn't read last frame's SkipItems
   5223    window->SkipItems = false;
   5224
   5225    // Draw window + handle manual resize
   5226    // 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.
   5227    const float window_rounding = window->WindowRounding;
   5228    const float window_border_size = window->WindowBorderSize;
   5229    if (window->Collapsed)
   5230    {
   5231        // Title bar only
   5232        float backup_border_size = style.FrameBorderSize;
   5233        g.Style.FrameBorderSize = window->WindowBorderSize;
   5234        ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
   5235        RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
   5236        g.Style.FrameBorderSize = backup_border_size;
   5237    }
   5238    else
   5239    {
   5240        // Window background
   5241        if (!(flags & ImGuiWindowFlags_NoBackground))
   5242        {
   5243            ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
   5244            bool override_alpha = false;
   5245            float alpha = 1.0f;
   5246            if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
   5247            {
   5248                alpha = g.NextWindowData.BgAlphaVal;
   5249                override_alpha = true;
   5250            }
   5251            if (override_alpha)
   5252                bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
   5253            window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
   5254        }
   5255
   5256        // Title bar
   5257        if (!(flags & ImGuiWindowFlags_NoTitleBar))
   5258        {
   5259            ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
   5260            window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
   5261        }
   5262
   5263        // Menu bar
   5264        if (flags & ImGuiWindowFlags_MenuBar)
   5265        {
   5266            ImRect menu_bar_rect = window->MenuBarRect();
   5267            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.
   5268            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);
   5269            if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
   5270                window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
   5271        }
   5272
   5273        // Scrollbars
   5274        if (window->ScrollbarX)
   5275            Scrollbar(ImGuiAxis_X);
   5276        if (window->ScrollbarY)
   5277            Scrollbar(ImGuiAxis_Y);
   5278
   5279        // Render resize grips (after their input handling so we don't have a frame of latency)
   5280        if (!(flags & ImGuiWindowFlags_NoResize))
   5281        {
   5282            for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
   5283            {
   5284                const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
   5285                const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
   5286                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)));
   5287                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)));
   5288                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);
   5289                window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
   5290            }
   5291        }
   5292
   5293        // Borders
   5294        RenderWindowOuterBorders(window);
   5295    }
   5296}
   5297
   5298// Render title text, collapse button, close button
   5299void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
   5300{
   5301    ImGuiContext& g = *GImGui;
   5302    ImGuiStyle& style = g.Style;
   5303    ImGuiWindowFlags flags = window->Flags;
   5304
   5305    const bool has_close_button = (p_open != NULL);
   5306    const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
   5307
   5308    // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
   5309    const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
   5310    window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
   5311    window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
   5312    window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
   5313
   5314    // Layout buttons
   5315    // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
   5316    float pad_l = style.FramePadding.x;
   5317    float pad_r = style.FramePadding.x;
   5318    float button_sz = g.FontSize;
   5319    ImVec2 close_button_pos;
   5320    ImVec2 collapse_button_pos;
   5321    if (has_close_button)
   5322    {
   5323        pad_r += button_sz;
   5324        close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
   5325    }
   5326    if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
   5327    {
   5328        pad_r += button_sz;
   5329        collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
   5330    }
   5331    if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
   5332    {
   5333        collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
   5334        pad_l += button_sz;
   5335    }
   5336
   5337    // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
   5338    if (has_collapse_button)
   5339        if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos))
   5340            window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
   5341
   5342    // Close button
   5343    if (has_close_button)
   5344        if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
   5345            *p_open = false;
   5346
   5347    window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
   5348    window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
   5349    window->DC.ItemFlags = item_flags_backup;
   5350
   5351    // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
   5352    // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
   5353    const char* UNSAVED_DOCUMENT_MARKER = "*";
   5354    const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
   5355    const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
   5356
   5357    // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
   5358    // while uncentered title text will still reach edges correct.
   5359    if (pad_l > style.FramePadding.x)
   5360        pad_l += g.Style.ItemInnerSpacing.x;
   5361    if (pad_r > style.FramePadding.x)
   5362        pad_r += g.Style.ItemInnerSpacing.x;
   5363    if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
   5364    {
   5365        float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
   5366        float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
   5367        pad_l = ImMax(pad_l, pad_extend * centerness);
   5368        pad_r = ImMax(pad_r, pad_extend * centerness);
   5369    }
   5370
   5371    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);
   5372    ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y);
   5373    //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
   5374    RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
   5375    if (flags & ImGuiWindowFlags_UnsavedDocument)
   5376    {
   5377        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);
   5378        ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f));
   5379        RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
   5380    }
   5381}
   5382
   5383void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
   5384{
   5385    window->ParentWindow = parent_window;
   5386    window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
   5387    if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
   5388        window->RootWindow = parent_window->RootWindow;
   5389    if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
   5390        window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
   5391    while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
   5392    {
   5393        IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
   5394        window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
   5395    }
   5396}
   5397
   5398// Push a new Dear ImGui window to add widgets to.
   5399// - 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.
   5400// - Begin/End can be called multiple times during the frame with the same window name to append content.
   5401// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
   5402//   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.
   5403// - 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.
   5404// - 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.
   5405bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
   5406{
   5407    ImGuiContext& g = *GImGui;
   5408    const ImGuiStyle& style = g.Style;
   5409    IM_ASSERT(name != NULL && name[0] != '\0');     // Window name required
   5410    IM_ASSERT(g.WithinFrameScope);                  // Forgot to call ImGui::NewFrame()
   5411    IM_ASSERT(g.FrameCountEnded != g.FrameCount);   // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
   5412
   5413    // Find or create
   5414    ImGuiWindow* window = FindWindowByName(name);
   5415    const bool window_just_created = (window == NULL);
   5416    if (window_just_created)
   5417    {
   5418        ImVec2 size_on_first_use = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
   5419        window = CreateNewWindow(name, size_on_first_use, flags);
   5420    }
   5421
   5422    // Automatically disable manual moving/resizing when NoInputs is set
   5423    if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
   5424        flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
   5425
   5426    if (flags & ImGuiWindowFlags_NavFlattened)
   5427        IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
   5428
   5429    const int current_frame = g.FrameCount;
   5430    const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
   5431    window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);
   5432
   5433    // Update the Appearing flag
   5434    bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1);   // Not using !WasActive because the implicit "Debug" window would always toggle off->on
   5435    const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
   5436    if (flags & ImGuiWindowFlags_Popup)
   5437    {
   5438        ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
   5439        window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
   5440        window_just_activated_by_user |= (window != popup_ref.Window);
   5441    }
   5442    window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
   5443    if (window->Appearing)
   5444        SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
   5445
   5446    // Update Flags, LastFrameActive, BeginOrderXXX fields
   5447    if (first_begin_of_the_frame)
   5448    {
   5449        window->Flags = (ImGuiWindowFlags)flags;
   5450        window->LastFrameActive = current_frame;
   5451        window->LastTimeActive = (float)g.Time;
   5452        window->BeginOrderWithinParent = 0;
   5453        window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
   5454    }
   5455    else
   5456    {
   5457        flags = window->Flags;
   5458    }
   5459
   5460    // 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
   5461    ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
   5462    ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
   5463    IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
   5464
   5465    // We allow window memory to be compacted so recreate the base stack when needed.
   5466    if (window->IDStack.Size == 0)
   5467        window->IDStack.push_back(window->ID);
   5468
   5469    // Add to stack
   5470    // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
   5471    g.CurrentWindowStack.push_back(window);
   5472    g.CurrentWindow = NULL;
   5473    ErrorCheckBeginEndCompareStacksSize(window, true);
   5474    if (flags & ImGuiWindowFlags_Popup)
   5475    {
   5476        ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
   5477        popup_ref.Window = window;
   5478        g.BeginPopupStack.push_back(popup_ref);
   5479        window->PopupId = popup_ref.PopupId;
   5480    }
   5481
   5482    if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow))
   5483        window->NavLastIds[0] = 0;
   5484
   5485    // Update ->RootWindow and others pointers (before any possible call to FocusWindow)
   5486    if (first_begin_of_the_frame)
   5487        UpdateWindowParentAndRootLinks(window, flags, parent_window);
   5488
   5489    // Process SetNextWindow***() calls
   5490    bool window_pos_set_by_api = false;
   5491    bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
   5492    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)
   5493    {
   5494        window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
   5495        if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
   5496        {
   5497            // May be processed on the next frame if this is our first frame and we are measuring size
   5498            // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
   5499            window->SetWindowPosVal = g.NextWindowData.PosVal;
   5500            window->SetWindowPosPivot = g.NextWindowData.PosPivotVal;
   5501            window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
   5502        }
   5503        else
   5504        {
   5505            SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
   5506        }
   5507    }
   5508    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)
   5509    {
   5510        window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
   5511        window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
   5512        SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
   5513    }
   5514    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)
   5515        window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal;
   5516    else if (first_begin_of_the_frame)
   5517        window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
   5518    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)
   5519        SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
   5520    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
   5521        FocusWindow(window);
   5522    if (window->Appearing)
   5523        SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
   5524
   5525    // When reusing window again multiple times a frame, just append content (don't need to setup again)
   5526    if (first_begin_of_the_frame)
   5527    {
   5528        // Initialize
   5529        const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
   5530        window->Active = true;
   5531        window->HasCloseButton = (p_open != NULL);
   5532        window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
   5533        window->IDStack.resize(1);
   5534
   5535        // Restore buffer capacity when woken from a compacted state, to avoid
   5536        if (window->MemoryCompacted)
   5537            GcAwakeTransientWindowBuffers(window);
   5538
   5539        // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
   5540        // 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.
   5541        bool window_title_visible_elsewhere = false;
   5542        if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0)   // Window titles visible when using CTRL+TAB
   5543            window_title_visible_elsewhere = true;
   5544        if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
   5545        {
   5546            size_t buf_len = (size_t)window->NameBufLen;
   5547            window->Name = ImStrdupcpy(window->Name, &buf_len, name);
   5548            window->NameBufLen = (int)buf_len;
   5549        }
   5550
   5551        // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
   5552
   5553        // Update contents size from last frame for auto-fitting (or use explicit size)
   5554        window->ContentSize = CalcWindowContentSize(window);
   5555        if (window->HiddenFramesCanSkipItems > 0)
   5556            window->HiddenFramesCanSkipItems--;
   5557        if (window->HiddenFramesCannotSkipItems > 0)
   5558            window->HiddenFramesCannotSkipItems--;
   5559
   5560        // Hide new windows for one frame until they calculate their size
   5561        if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
   5562            window->HiddenFramesCannotSkipItems = 1;
   5563
   5564        // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
   5565        // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
   5566        if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
   5567        {
   5568            window->HiddenFramesCannotSkipItems = 1;
   5569            if (flags & ImGuiWindowFlags_AlwaysAutoResize)
   5570            {
   5571                if (!window_size_x_set_by_api)
   5572                    window->Size.x = window->SizeFull.x = 0.f;
   5573                if (!window_size_y_set_by_api)
   5574                    window->Size.y = window->SizeFull.y = 0.f;
   5575                window->ContentSize = ImVec2(0.f, 0.f);
   5576            }
   5577        }
   5578
   5579        // SELECT VIEWPORT
   5580        // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style)
   5581        SetCurrentWindow(window);
   5582
   5583        // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)
   5584
   5585        if (flags & ImGuiWindowFlags_ChildWindow)
   5586            window->WindowBorderSize = style.ChildBorderSize;
   5587        else
   5588            window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
   5589        window->WindowPadding = style.WindowPadding;
   5590        if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)
   5591            window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
   5592
   5593        // Collapse window by double-clicking on title bar
   5594        // 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
   5595        if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
   5596        {
   5597            // 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.
   5598            ImRect title_bar_rect = window->TitleBarRect();
   5599            if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])
   5600                window->WantCollapseToggle = true;
   5601            if (window->WantCollapseToggle)
   5602            {
   5603                window->Collapsed = !window->Collapsed;
   5604                MarkIniSettingsDirty(window);
   5605                FocusWindow(window);
   5606            }
   5607        }
   5608        else
   5609        {
   5610            window->Collapsed = false;
   5611        }
   5612        window->WantCollapseToggle = false;
   5613
   5614        // SIZE
   5615
   5616        // Calculate auto-fit size, handle automatic resize
   5617        const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSize);
   5618        bool use_current_size_for_scrollbar_x = window_just_created;
   5619        bool use_current_size_for_scrollbar_y = window_just_created;
   5620        if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
   5621        {
   5622            // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
   5623            if (!window_size_x_set_by_api)
   5624            {
   5625                window->SizeFull.x = size_auto_fit.x;
   5626                use_current_size_for_scrollbar_x = true;
   5627            }
   5628            if (!window_size_y_set_by_api)
   5629            {
   5630                window->SizeFull.y = size_auto_fit.y;
   5631                use_current_size_for_scrollbar_y = true;
   5632            }
   5633        }
   5634        else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
   5635        {
   5636            // Auto-fit may only grow window during the first few frames
   5637            // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
   5638            if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
   5639            {
   5640                window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
   5641                use_current_size_for_scrollbar_x = true;
   5642            }
   5643            if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
   5644            {
   5645                window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
   5646                use_current_size_for_scrollbar_y = true;
   5647            }
   5648            if (!window->Collapsed)
   5649                MarkIniSettingsDirty(window);
   5650        }
   5651
   5652        // Apply minimum/maximum window size constraints and final size
   5653        window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);
   5654        window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
   5655
   5656        // Decoration size
   5657        const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
   5658
   5659        // POSITION
   5660
   5661        // Popup latch its initial position, will position itself when it appears next frame
   5662        if (window_just_activated_by_user)
   5663        {
   5664            window->AutoPosLastDirection = ImGuiDir_None;
   5665            if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
   5666                window->Pos = g.BeginPopupStack.back().OpenPopupPos;
   5667        }
   5668
   5669        // Position child window
   5670        if (flags & ImGuiWindowFlags_ChildWindow)
   5671        {
   5672            IM_ASSERT(parent_window && parent_window->Active);
   5673            window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
   5674            parent_window->DC.ChildWindows.push_back(window);
   5675            if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
   5676                window->Pos = parent_window->DC.CursorPos;
   5677        }
   5678
   5679        const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);
   5680        if (window_pos_with_pivot)
   5681            SetWindowPos(window, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering)
   5682        else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
   5683            window->Pos = FindBestWindowPosForPopup(window);
   5684        else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
   5685            window->Pos = FindBestWindowPosForPopup(window);
   5686        else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
   5687            window->Pos = FindBestWindowPosForPopup(window);
   5688
   5689        // Clamp position/size so window stays visible within its viewport or monitor
   5690        // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
   5691        ImRect viewport_rect(GetViewportRect());
   5692        if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
   5693        {
   5694            ImVec2 clamp_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
   5695            if (viewport_rect.GetWidth() > 0 && viewport_rect.GetHeight() > 0.0f)
   5696            {
   5697                ClampWindowRect(window, viewport_rect, clamp_padding);
   5698            }
   5699        }
   5700        window->Pos = ImFloor(window->Pos);
   5701
   5702        // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
   5703        window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
   5704
   5705        // Apply window focus (new and reactivated windows are moved to front)
   5706        bool want_focus = false;
   5707        if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
   5708        {
   5709            if (flags & ImGuiWindowFlags_Popup)
   5710                want_focus = true;
   5711            else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
   5712                want_focus = true;
   5713        }
   5714
   5715        // Handle manual resize: Resize Grips, Borders, Gamepad
   5716        int border_held = -1;
   5717        ImU32 resize_grip_col[4] = {};
   5718        const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
   5719        const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
   5720        if (!window->Collapsed)
   5721            if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]))
   5722                use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
   5723        window->ResizeBorderHeld = (signed char)border_held;
   5724
   5725        // SCROLLBAR VISIBILITY
   5726
   5727        // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).
   5728        if (!window->Collapsed)
   5729        {
   5730            // When reading the current size we need to read it after size constraints have been applied.
   5731            // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again.
   5732            ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height);
   5733            ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes;
   5734            ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
   5735            float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
   5736            float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
   5737            //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
   5738            window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
   5739            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));
   5740            if (window->ScrollbarX && !window->ScrollbarY)
   5741                window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
   5742            window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
   5743        }
   5744
   5745        // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)
   5746        // Update various regions. Variables they depends on should be set above in this function.
   5747        // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.
   5748
   5749        // Outer rectangle
   5750        // Not affected by window border size. Used by:
   5751        // - FindHoveredWindow() (w/ extra padding when border resize is enabled)
   5752        // - Begin() initial clipping rect for drawing window background and borders.
   5753        // - Begin() clipping whole child
   5754        const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
   5755        const ImRect outer_rect = window->Rect();
   5756        const ImRect title_bar_rect = window->TitleBarRect();
   5757        window->OuterRectClipped = outer_rect;
   5758        window->OuterRectClipped.ClipWith(host_rect);
   5759
   5760        // Inner rectangle
   5761        // Not affected by window border size. Used by:
   5762        // - InnerClipRect
   5763        // - ScrollToBringRectIntoView()
   5764        // - NavUpdatePageUpPageDown()
   5765        // - Scrollbar()
   5766        window->InnerRect.Min.x = window->Pos.x;
   5767        window->InnerRect.Min.y = window->Pos.y + decoration_up_height;
   5768        window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x;
   5769        window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y;
   5770
   5771        // Inner clipping rectangle.
   5772        // Will extend a little bit outside the normal work region.
   5773        // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
   5774        // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
   5775        // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
   5776        // Affected by window/frame border size. Used by:
   5777        // - Begin() initial clip rect
   5778        float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
   5779        window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
   5780        window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
   5781        window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
   5782        window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
   5783        window->InnerClipRect.ClipWithFull(host_rect);
   5784
   5785        // Default item width. Make it proportional to window size if window manually resizes
   5786        if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
   5787            window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f);
   5788        else
   5789            window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f);
   5790
   5791        // SCROLLING
   5792
   5793        // Lock down maximum scrolling
   5794        // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate
   5795        // for right/bottom aligned items without creating a scrollbar.
   5796        window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
   5797        window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
   5798
   5799        // Apply scrolling
   5800        window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true);
   5801        window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
   5802
   5803        // DRAWING
   5804
   5805        // Setup draw list and outer clipping rectangle
   5806        window->DrawList->Clear();
   5807        window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
   5808        PushClipRect(host_rect.Min, host_rect.Max, false);
   5809
   5810        // Draw modal window background (darkens what is behind them, all viewports)
   5811        const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
   5812        const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow);
   5813        if (dim_bg_for_modal || dim_bg_for_window_list)
   5814        {
   5815            const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
   5816            window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col);
   5817        }
   5818
   5819        // Draw navigation selection/windowing rectangle background
   5820        if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim)
   5821        {
   5822            ImRect bb = window->Rect();
   5823            bb.Expand(g.FontSize);
   5824            if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
   5825                window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
   5826        }
   5827
   5828        // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call.
   5829        // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
   5830        // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child.
   5831        // We also disabled this when we have dimming overlay behind this specific one child.
   5832        // 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.
   5833        {
   5834            bool render_decorations_in_parent = false;
   5835            if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
   5836                if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0)
   5837                    render_decorations_in_parent = true;
   5838            if (render_decorations_in_parent)
   5839                window->DrawList = parent_window->DrawList;
   5840
   5841            // Handle title bar, scrollbar, resize grips and resize borders
   5842            const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
   5843            const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
   5844            RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size);
   5845
   5846            if (render_decorations_in_parent)
   5847                window->DrawList = &window->DrawListInst;
   5848        }
   5849
   5850        // Draw navigation selection/windowing rectangle border
   5851        if (g.NavWindowingTargetAnim == window)
   5852        {
   5853            float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
   5854            ImRect bb = window->Rect();
   5855            bb.Expand(g.FontSize);
   5856            if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
   5857            {
   5858                bb.Expand(-g.FontSize - 1.0f);
   5859                rounding = window->WindowRounding;
   5860            }
   5861            window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
   5862        }
   5863
   5864        // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
   5865
   5866        // Work rectangle.
   5867        // Affected by window padding and border size. Used by:
   5868        // - Columns() for right-most edge
   5869        // - TreeNode(), CollapsingHeader() for right-most edge
   5870        // - BeginTabBar() for right-most edge
   5871        const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
   5872        const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
   5873        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));
   5874        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));
   5875        window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
   5876        window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
   5877        window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
   5878        window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
   5879
   5880        // [LEGACY] Content Region
   5881        // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
   5882        // Used by:
   5883        // - Mouse wheel scrolling + many other things
   5884        window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
   5885        window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
   5886        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));
   5887        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));
   5888
   5889        // Setup drawing context
   5890        // (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.)
   5891        window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
   5892        window->DC.GroupOffset.x = 0.0f;
   5893        window->DC.ColumnsOffset.x = 0.0f;
   5894        window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y);
   5895        window->DC.CursorPos = window->DC.CursorStartPos;
   5896        window->DC.CursorPosPrevLine = window->DC.CursorPos;
   5897        window->DC.CursorMaxPos = window->DC.CursorStartPos;
   5898        window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
   5899        window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
   5900
   5901        window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
   5902        window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
   5903        window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
   5904        window->DC.NavLayerActiveMaskNext = 0x00;
   5905        window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // -V595
   5906        window->DC.NavHideHighlightOneFrame = false;
   5907        window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
   5908
   5909        window->DC.MenuBarAppending = false;
   5910        window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
   5911        window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
   5912        window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
   5913        window->DC.TreeDepth = 0;
   5914        window->DC.TreeJumpToParentOnPopMask = 0x00;
   5915        window->DC.ChildWindows.resize(0);
   5916        window->DC.StateStorage = &window->StateStorage;
   5917        window->DC.CurrentColumns = NULL;
   5918        window->DC.LayoutType = ImGuiLayoutType_Vertical;
   5919        window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
   5920        window->DC.FocusCounterRegular = window->DC.FocusCounterTabStop = -1;
   5921
   5922        window->DC.ItemWidth = window->ItemWidthDefault;
   5923        window->DC.TextWrapPos = -1.0f; // disabled
   5924        window->DC.ItemFlagsStack.resize(0);
   5925        window->DC.ItemWidthStack.resize(0);
   5926        window->DC.TextWrapPosStack.resize(0);
   5927        window->DC.GroupStack.resize(0);
   5928        window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_;
   5929        if (parent_window)
   5930            window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
   5931
   5932        if (window->AutoFitFramesX > 0)
   5933            window->AutoFitFramesX--;
   5934        if (window->AutoFitFramesY > 0)
   5935            window->AutoFitFramesY--;
   5936
   5937        // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
   5938        if (want_focus)
   5939        {
   5940            FocusWindow(window);
   5941            NavInitWindow(window, false);
   5942        }
   5943
   5944        // Title bar
   5945        if (!(flags & ImGuiWindowFlags_NoTitleBar))
   5946            RenderWindowTitleBarContents(window, title_bar_rect, name, p_open);
   5947
   5948        // Pressing CTRL+C while holding on a window copy its content to the clipboard
   5949        // 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.
   5950        // Maybe we can support CTRL+C on every element?
   5951        /*
   5952        if (g.ActiveId == move_id)
   5953            if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
   5954                LogToClipboard();
   5955        */
   5956
   5957        // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
   5958        // This is useful to allow creating context menus on title bar only, etc.
   5959        window->DC.LastItemId = window->MoveId;
   5960        window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
   5961        window->DC.LastItemRect = title_bar_rect;
   5962#ifdef IMGUI_ENABLE_TEST_ENGINE
   5963        if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
   5964            IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId);
   5965#endif
   5966    }
   5967    else
   5968    {
   5969        // Append
   5970        SetCurrentWindow(window);
   5971    }
   5972
   5973    PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
   5974
   5975    // 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)
   5976    if (first_begin_of_the_frame)
   5977        window->WriteAccessed = false;
   5978
   5979    window->BeginCount++;
   5980    g.NextWindowData.ClearFlags();
   5981
   5982    if (flags & ImGuiWindowFlags_ChildWindow)
   5983    {
   5984        // Child window can be out of sight and have "negative" clip windows.
   5985        // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
   5986        IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
   5987        if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
   5988            if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
   5989                window->HiddenFramesCanSkipItems = 1;
   5990
   5991        // Hide along with parent or if parent is collapsed
   5992        if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
   5993            window->HiddenFramesCanSkipItems = 1;
   5994        if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
   5995            window->HiddenFramesCannotSkipItems = 1;
   5996    }
   5997
   5998    // 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)
   5999    if (style.Alpha <= 0.0f)
   6000        window->HiddenFramesCanSkipItems = 1;
   6001
   6002    // Update the Hidden flag
   6003    window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
   6004
   6005    // Update the SkipItems flag, used to early out of all items functions (no layout required)
   6006    bool skip_items = false;
   6007    if (window->Collapsed || !window->Active || window->Hidden)
   6008        if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
   6009            skip_items = true;
   6010    window->SkipItems = skip_items;
   6011
   6012    return !skip_items;
   6013}
   6014
   6015void ImGui::End()
   6016{
   6017    ImGuiContext& g = *GImGui;
   6018    ImGuiWindow* window = g.CurrentWindow;
   6019
   6020    // Error checking: verify that user hasn't called End() too many times!
   6021    if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow)
   6022    {
   6023        IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
   6024        return;
   6025    }
   6026    IM_ASSERT(g.CurrentWindowStack.Size > 0);
   6027
   6028    // Error checking: verify that user doesn't directly call End() on a child window.
   6029    if (window->Flags & ImGuiWindowFlags_ChildWindow)
   6030        IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!");
   6031
   6032    // Close anything that is open
   6033    if (window->DC.CurrentColumns)
   6034        EndColumns();
   6035    PopClipRect();   // Inner window clip rectangle
   6036
   6037    // Stop logging
   6038    if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging
   6039        LogFinish();
   6040
   6041    // Pop from window stack
   6042    g.CurrentWindowStack.pop_back();
   6043    if (window->Flags & ImGuiWindowFlags_Popup)
   6044        g.BeginPopupStack.pop_back();
   6045    ErrorCheckBeginEndCompareStacksSize(window, false);
   6046    SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
   6047}
   6048
   6049void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
   6050{
   6051    ImGuiContext& g = *GImGui;
   6052    if (g.WindowsFocusOrder.back() == window)
   6053        return;
   6054    for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window
   6055        if (g.WindowsFocusOrder[i] == window)
   6056        {
   6057            memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
   6058            g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window;
   6059            break;
   6060        }
   6061}
   6062
   6063void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
   6064{
   6065    ImGuiContext& g = *GImGui;
   6066    ImGuiWindow* current_front_window = g.Windows.back();
   6067    if (current_front_window == window || current_front_window->RootWindow == window)
   6068        return;
   6069    for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
   6070        if (g.Windows[i] == window)
   6071        {
   6072            memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
   6073            g.Windows[g.Windows.Size - 1] = window;
   6074            break;
   6075        }
   6076}
   6077
   6078void ImGui::BringWindowToDisplayBack(ImGuiWindow* window)
   6079{
   6080    ImGuiContext& g = *GImGui;
   6081    if (g.Windows[0] == window)
   6082        return;
   6083    for (int i = 0; i < g.Windows.Size; i++)
   6084        if (g.Windows[i] == window)
   6085        {
   6086            memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
   6087            g.Windows[0] = window;
   6088            break;
   6089        }
   6090}
   6091
   6092// Moving window to front of display and set focus (which happens to be back of our sorted list)
   6093void ImGui::FocusWindow(ImGuiWindow* window)
   6094{
   6095    ImGuiContext& g = *GImGui;
   6096
   6097    if (g.NavWindow != window)
   6098    {
   6099        g.NavWindow = window;
   6100        if (window && g.NavDisableMouseHover)
   6101            g.NavMousePosDirty = true;
   6102        g.NavInitRequest = false;
   6103        g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
   6104        g.NavFocusScopeId = 0;
   6105        g.NavIdIsAlive = false;
   6106        g.NavLayer = ImGuiNavLayer_Main;
   6107        //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
   6108    }
   6109
   6110    // Close popups if any
   6111    ClosePopupsOverWindow(window, false);
   6112
   6113    // Passing NULL allow to disable keyboard focus
   6114    if (!window)
   6115        return;
   6116
   6117    // Move the root window to the top of the pile
   6118    IM_ASSERT(window->RootWindow != NULL);
   6119    ImGuiWindow* focus_front_window = window->RootWindow; // NB: In docking branch this is window->RootWindowDockStop
   6120    ImGuiWindow* display_front_window = window->RootWindow;
   6121
   6122    // Steal focus on active widgets
   6123    if (focus_front_window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement may be unnecessary? Need further testing before removing it..
   6124        if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)
   6125            ClearActiveID();
   6126
   6127    // Bring to front
   6128    BringWindowToFocusFront(focus_front_window);
   6129    if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
   6130        BringWindowToDisplayFront(display_front_window);
   6131}
   6132
   6133void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window)
   6134{
   6135    ImGuiContext& g = *GImGui;
   6136
   6137    int start_idx = g.WindowsFocusOrder.Size - 1;
   6138    if (under_this_window != NULL)
   6139    {
   6140        int under_this_window_idx = FindWindowFocusIndex(under_this_window);
   6141        if (under_this_window_idx != -1)
   6142            start_idx = under_this_window_idx - 1;
   6143    }
   6144    for (int i = start_idx; i >= 0; i--)
   6145    {
   6146        // 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.
   6147        ImGuiWindow* window = g.WindowsFocusOrder[i];
   6148        if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow))
   6149            if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
   6150            {
   6151                ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
   6152                FocusWindow(focus_window);
   6153                return;
   6154            }
   6155    }
   6156    FocusWindow(NULL);
   6157}
   6158
   6159void ImGui::SetCurrentFont(ImFont* font)
   6160{
   6161    ImGuiContext& g = *GImGui;
   6162    IM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
   6163    IM_ASSERT(font->Scale > 0.0f);
   6164    g.Font = font;
   6165    g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
   6166    g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
   6167
   6168    ImFontAtlas* atlas = g.Font->ContainerAtlas;
   6169    g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
   6170    g.DrawListSharedData.Font = g.Font;
   6171    g.DrawListSharedData.FontSize = g.FontSize;
   6172}
   6173
   6174void ImGui::PushFont(ImFont* font)
   6175{
   6176    ImGuiContext& g = *GImGui;
   6177    if (!font)
   6178        font = GetDefaultFont();
   6179    SetCurrentFont(font);
   6180    g.FontStack.push_back(font);
   6181    g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
   6182}
   6183
   6184void  ImGui::PopFont()
   6185{
   6186    ImGuiContext& g = *GImGui;
   6187    g.CurrentWindow->DrawList->PopTextureID();
   6188    g.FontStack.pop_back();
   6189    SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
   6190}
   6191
   6192void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
   6193{
   6194    ImGuiWindow* window = GetCurrentWindow();
   6195    if (enabled)
   6196        window->DC.ItemFlags |= option;
   6197    else
   6198        window->DC.ItemFlags &= ~option;
   6199    window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
   6200}
   6201
   6202void ImGui::PopItemFlag()
   6203{
   6204    ImGuiWindow* window = GetCurrentWindow();
   6205    window->DC.ItemFlagsStack.pop_back();
   6206    window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back();
   6207}
   6208
   6209// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system.
   6210void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
   6211{
   6212    PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus);
   6213}
   6214
   6215void ImGui::PopAllowKeyboardFocus()
   6216{
   6217    PopItemFlag();
   6218}
   6219
   6220void ImGui::PushButtonRepeat(bool repeat)
   6221{
   6222    PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);
   6223}
   6224
   6225void ImGui::PopButtonRepeat()
   6226{
   6227    PopItemFlag();
   6228}
   6229
   6230void ImGui::PushTextWrapPos(float wrap_pos_x)
   6231{
   6232    ImGuiWindow* window = GetCurrentWindow();
   6233    window->DC.TextWrapPos = wrap_pos_x;
   6234    window->DC.TextWrapPosStack.push_back(wrap_pos_x);
   6235}
   6236
   6237void ImGui::PopTextWrapPos()
   6238{
   6239    ImGuiWindow* window = GetCurrentWindow();
   6240    window->DC.TextWrapPosStack.pop_back();
   6241    window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
   6242}
   6243
   6244bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
   6245{
   6246    if (window->RootWindow == potential_parent)
   6247        return true;
   6248    while (window != NULL)
   6249    {
   6250        if (window == potential_parent)
   6251            return true;
   6252        window = window->ParentWindow;
   6253    }
   6254    return false;
   6255}
   6256
   6257bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)
   6258{
   6259    IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0);   // Flags not supported by this function
   6260    ImGuiContext& g = *GImGui;
   6261
   6262    if (flags & ImGuiHoveredFlags_AnyWindow)
   6263    {
   6264        if (g.HoveredWindow == NULL)
   6265            return false;
   6266    }
   6267    else
   6268    {
   6269        switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows))
   6270        {
   6271        case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows:
   6272            if (g.HoveredRootWindow != g.CurrentWindow->RootWindow)
   6273                return false;
   6274            break;
   6275        case ImGuiHoveredFlags_RootWindow:
   6276            if (g.HoveredWindow != g.CurrentWindow->RootWindow)
   6277                return false;
   6278            break;
   6279        case ImGuiHoveredFlags_ChildWindows:
   6280            if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow))
   6281                return false;
   6282            break;
   6283        default:
   6284            if (g.HoveredWindow != g.CurrentWindow)
   6285                return false;
   6286            break;
   6287        }
   6288    }
   6289
   6290    if (!IsWindowContentHoverable(g.HoveredWindow, flags))
   6291        return false;
   6292    if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
   6293        if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
   6294            return false;
   6295    return true;
   6296}
   6297
   6298bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
   6299{
   6300    ImGuiContext& g = *GImGui;
   6301
   6302    if (flags & ImGuiFocusedFlags_AnyWindow)
   6303        return g.NavWindow != NULL;
   6304
   6305    IM_ASSERT(g.CurrentWindow);     // Not inside a Begin()/End()
   6306    switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))
   6307    {
   6308    case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:
   6309        return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
   6310    case ImGuiFocusedFlags_RootWindow:
   6311        return g.NavWindow == g.CurrentWindow->RootWindow;
   6312    case ImGuiFocusedFlags_ChildWindows:
   6313        return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
   6314    default:
   6315        return g.NavWindow == g.CurrentWindow;
   6316    }
   6317}
   6318
   6319// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
   6320// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmaticaly.
   6321// If you want a window to never be focused, you may use the e.g. NoInputs flag.
   6322bool ImGui::IsWindowNavFocusable(ImGuiWindow* window)
   6323{
   6324    return window->Active && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);
   6325}
   6326
   6327float ImGui::GetWindowWidth()
   6328{
   6329    ImGuiWindow* window = GImGui->CurrentWindow;
   6330    return window->Size.x;
   6331}
   6332
   6333float ImGui::GetWindowHeight()
   6334{
   6335    ImGuiWindow* window = GImGui->CurrentWindow;
   6336    return window->Size.y;
   6337}
   6338
   6339ImVec2 ImGui::GetWindowPos()
   6340{
   6341    ImGuiContext& g = *GImGui;
   6342    ImGuiWindow* window = g.CurrentWindow;
   6343    return window->Pos;
   6344}
   6345
   6346void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
   6347{
   6348    // Test condition (NB: bit 0 is always true) and clear flags for next time
   6349    if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
   6350        return;
   6351
   6352    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6353    window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
   6354    window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
   6355
   6356    // Set
   6357    const ImVec2 old_pos = window->Pos;
   6358    window->Pos = ImFloor(pos);
   6359    ImVec2 offset = window->Pos - old_pos;
   6360    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
   6361    window->DC.CursorMaxPos += offset;      // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
   6362    window->DC.CursorStartPos += offset;
   6363}
   6364
   6365void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
   6366{
   6367    ImGuiWindow* window = GetCurrentWindowRead();
   6368    SetWindowPos(window, pos, cond);
   6369}
   6370
   6371void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
   6372{
   6373    if (ImGuiWindow* window = FindWindowByName(name))
   6374        SetWindowPos(window, pos, cond);
   6375}
   6376
   6377ImVec2 ImGui::GetWindowSize()
   6378{
   6379    ImGuiWindow* window = GetCurrentWindowRead();
   6380    return window->Size;
   6381}
   6382
   6383void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
   6384{
   6385    // Test condition (NB: bit 0 is always true) and clear flags for next time
   6386    if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
   6387        return;
   6388
   6389    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6390    window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
   6391
   6392    // Set
   6393    if (size.x > 0.0f)
   6394    {
   6395        window->AutoFitFramesX = 0;
   6396        window->SizeFull.x = IM_FLOOR(size.x);
   6397    }
   6398    else
   6399    {
   6400        window->AutoFitFramesX = 2;
   6401        window->AutoFitOnlyGrows = false;
   6402    }
   6403    if (size.y > 0.0f)
   6404    {
   6405        window->AutoFitFramesY = 0;
   6406        window->SizeFull.y = IM_FLOOR(size.y);
   6407    }
   6408    else
   6409    {
   6410        window->AutoFitFramesY = 2;
   6411        window->AutoFitOnlyGrows = false;
   6412    }
   6413}
   6414
   6415void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
   6416{
   6417    SetWindowSize(GImGui->CurrentWindow, size, cond);
   6418}
   6419
   6420void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
   6421{
   6422    if (ImGuiWindow* window = FindWindowByName(name))
   6423        SetWindowSize(window, size, cond);
   6424}
   6425
   6426void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
   6427{
   6428    // Test condition (NB: bit 0 is always true) and clear flags for next time
   6429    if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
   6430        return;
   6431    window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
   6432
   6433    // Set
   6434    window->Collapsed = collapsed;
   6435}
   6436
   6437void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
   6438{
   6439    SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
   6440}
   6441
   6442bool ImGui::IsWindowCollapsed()
   6443{
   6444    ImGuiWindow* window = GetCurrentWindowRead();
   6445    return window->Collapsed;
   6446}
   6447
   6448bool ImGui::IsWindowAppearing()
   6449{
   6450    ImGuiWindow* window = GetCurrentWindowRead();
   6451    return window->Appearing;
   6452}
   6453
   6454void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
   6455{
   6456    if (ImGuiWindow* window = FindWindowByName(name))
   6457        SetWindowCollapsed(window, collapsed, cond);
   6458}
   6459
   6460void ImGui::SetWindowFocus()
   6461{
   6462    FocusWindow(GImGui->CurrentWindow);
   6463}
   6464
   6465void ImGui::SetWindowFocus(const char* name)
   6466{
   6467    if (name)
   6468    {
   6469        if (ImGuiWindow* window = FindWindowByName(name))
   6470            FocusWindow(window);
   6471    }
   6472    else
   6473    {
   6474        FocusWindow(NULL);
   6475    }
   6476}
   6477
   6478void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
   6479{
   6480    ImGuiContext& g = *GImGui;
   6481    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6482    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;
   6483    g.NextWindowData.PosVal = pos;
   6484    g.NextWindowData.PosPivotVal = pivot;
   6485    g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
   6486}
   6487
   6488void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
   6489{
   6490    ImGuiContext& g = *GImGui;
   6491    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6492    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;
   6493    g.NextWindowData.SizeVal = size;
   6494    g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
   6495}
   6496
   6497void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
   6498{
   6499    ImGuiContext& g = *GImGui;
   6500    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
   6501    g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
   6502    g.NextWindowData.SizeCallback = custom_callback;
   6503    g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
   6504}
   6505
   6506// Content size = inner scrollable rectangle, padded with WindowPadding.
   6507// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
   6508void ImGui::SetNextWindowContentSize(const ImVec2& size)
   6509{
   6510    ImGuiContext& g = *GImGui;
   6511    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;
   6512    g.NextWindowData.ContentSizeVal = size;
   6513}
   6514
   6515void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
   6516{
   6517    ImGuiContext& g = *GImGui;
   6518    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6519    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;
   6520    g.NextWindowData.CollapsedVal = collapsed;
   6521    g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
   6522}
   6523
   6524void ImGui::SetNextWindowFocus()
   6525{
   6526    ImGuiContext& g = *GImGui;
   6527    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;
   6528}
   6529
   6530void ImGui::SetNextWindowBgAlpha(float alpha)
   6531{
   6532    ImGuiContext& g = *GImGui;
   6533    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;
   6534    g.NextWindowData.BgAlphaVal = alpha;
   6535}
   6536
   6537ImDrawList* ImGui::GetWindowDrawList()
   6538{
   6539    ImGuiWindow* window = GetCurrentWindow();
   6540    return window->DrawList;
   6541}
   6542
   6543ImFont* ImGui::GetFont()
   6544{
   6545    return GImGui->Font;
   6546}
   6547
   6548float ImGui::GetFontSize()
   6549{
   6550    return GImGui->FontSize;
   6551}
   6552
   6553ImVec2 ImGui::GetFontTexUvWhitePixel()
   6554{
   6555    return GImGui->DrawListSharedData.TexUvWhitePixel;
   6556}
   6557
   6558void ImGui::SetWindowFontScale(float scale)
   6559{
   6560    ImGuiContext& g = *GImGui;
   6561    ImGuiWindow* window = GetCurrentWindow();
   6562    window->FontWindowScale = scale;
   6563    g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
   6564}
   6565
   6566void ImGui::ActivateItem(ImGuiID id)
   6567{
   6568    ImGuiContext& g = *GImGui;
   6569    g.NavNextActivateId = id;
   6570}
   6571
   6572void ImGui::PushFocusScope(ImGuiID id)
   6573{
   6574    ImGuiContext& g = *GImGui;
   6575    ImGuiWindow* window = g.CurrentWindow;
   6576    window->IDStack.push_back(window->DC.NavFocusScopeIdCurrent);
   6577    window->DC.NavFocusScopeIdCurrent = id;
   6578}
   6579
   6580void ImGui::PopFocusScope()
   6581{
   6582    ImGuiContext& g = *GImGui;
   6583    ImGuiWindow* window = g.CurrentWindow;
   6584    window->DC.NavFocusScopeIdCurrent = window->IDStack.back();
   6585    window->IDStack.pop_back();
   6586}
   6587
   6588void ImGui::SetKeyboardFocusHere(int offset)
   6589{
   6590    IM_ASSERT(offset >= -1);    // -1 is allowed but not below
   6591    ImGuiContext& g = *GImGui;
   6592    ImGuiWindow* window = g.CurrentWindow;
   6593    g.FocusRequestNextWindow = window;
   6594    g.FocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset;
   6595    g.FocusRequestNextCounterTabStop = INT_MAX;
   6596}
   6597
   6598void ImGui::SetItemDefaultFocus()
   6599{
   6600    ImGuiContext& g = *GImGui;
   6601    ImGuiWindow* window = g.CurrentWindow;
   6602    if (!window->Appearing)
   6603        return;
   6604    if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
   6605    {
   6606        g.NavInitRequest = false;
   6607        g.NavInitResultId = g.NavWindow->DC.LastItemId;
   6608        g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
   6609        NavUpdateAnyRequestFlag();
   6610        if (!IsItemVisible())
   6611            SetScrollHereY();
   6612    }
   6613}
   6614
   6615void ImGui::SetStateStorage(ImGuiStorage* tree)
   6616{
   6617    ImGuiWindow* window = GImGui->CurrentWindow;
   6618    window->DC.StateStorage = tree ? tree : &window->StateStorage;
   6619}
   6620
   6621ImGuiStorage* ImGui::GetStateStorage()
   6622{
   6623    ImGuiWindow* window = GImGui->CurrentWindow;
   6624    return window->DC.StateStorage;
   6625}
   6626
   6627void ImGui::PushID(const char* str_id)
   6628{
   6629    ImGuiWindow* window = GImGui->CurrentWindow;
   6630    window->IDStack.push_back(window->GetIDNoKeepAlive(str_id));
   6631}
   6632
   6633void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
   6634{
   6635    ImGuiWindow* window = GImGui->CurrentWindow;
   6636    window->IDStack.push_back(window->GetIDNoKeepAlive(str_id_begin, str_id_end));
   6637}
   6638
   6639void ImGui::PushID(const void* ptr_id)
   6640{
   6641    ImGuiWindow* window = GImGui->CurrentWindow;
   6642    window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id));
   6643}
   6644
   6645void ImGui::PushID(int int_id)
   6646{
   6647    ImGuiWindow* window = GImGui->CurrentWindow;
   6648    window->IDStack.push_back(window->GetIDNoKeepAlive(int_id));
   6649}
   6650
   6651// Push a given id value ignoring the ID stack as a seed.
   6652void ImGui::PushOverrideID(ImGuiID id)
   6653{
   6654    ImGuiWindow* window = GImGui->CurrentWindow;
   6655    window->IDStack.push_back(id);
   6656}
   6657
   6658void ImGui::PopID()
   6659{
   6660    ImGuiWindow* window = GImGui->CurrentWindow;
   6661    window->IDStack.pop_back();
   6662}
   6663
   6664ImGuiID ImGui::GetID(const char* str_id)
   6665{
   6666    ImGuiWindow* window = GImGui->CurrentWindow;
   6667    return window->GetID(str_id);
   6668}
   6669
   6670ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
   6671{
   6672    ImGuiWindow* window = GImGui->CurrentWindow;
   6673    return window->GetID(str_id_begin, str_id_end);
   6674}
   6675
   6676ImGuiID ImGui::GetID(const void* ptr_id)
   6677{
   6678    ImGuiWindow* window = GImGui->CurrentWindow;
   6679    return window->GetID(ptr_id);
   6680}
   6681
   6682bool ImGui::IsRectVisible(const ImVec2& size)
   6683{
   6684    ImGuiWindow* window = GImGui->CurrentWindow;
   6685    return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
   6686}
   6687
   6688bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
   6689{
   6690    ImGuiWindow* window = GImGui->CurrentWindow;
   6691    return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
   6692}
   6693
   6694
   6695//-----------------------------------------------------------------------------
   6696// [SECTION] ERROR CHECKING
   6697//-----------------------------------------------------------------------------
   6698
   6699// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
   6700// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
   6701// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
   6702// may see different structures than what imgui.cpp sees, which is problematic.
   6703// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui.
   6704bool 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)
   6705{
   6706    bool error = false;
   6707    if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); }
   6708    if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
   6709    if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
   6710    if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
   6711    if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
   6712    if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
   6713    if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); }
   6714    return !error;
   6715}
   6716
   6717static void ImGui::ErrorCheckNewFrameSanityChecks()
   6718{
   6719    ImGuiContext& g = *GImGui;
   6720
   6721    // Check user IM_ASSERT macro
   6722    // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means you assert macro is incorrectly defined!
   6723    //  If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block.
   6724    //  This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.)
   6725    // #define IM_ASSERT(EXPR)   SomeCode(EXPR); SomeMoreCode();                    // Wrong!
   6726    // #define IM_ASSERT(EXPR)   do { SomeCode(EXPR); SomeMoreCode(); } while (0)   // Correct!
   6727    if (true) IM_ASSERT(1); else IM_ASSERT(0);
   6728
   6729    // Check user data
   6730    // (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)
   6731    IM_ASSERT(g.Initialized);
   6732    IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0)              && "Need a positive DeltaTime!");
   6733    IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount)  && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
   6734    IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f  && "Invalid DisplaySize value!");
   6735    IM_ASSERT(g.IO.Fonts->Fonts.Size > 0                                && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
   6736    IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()                          && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
   6737    IM_ASSERT(g.Style.CurveTessellationTol > 0.0f                       && "Invalid style setting!");
   6738    IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f                      && "Invalid style setting!");
   6739    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)!");
   6740    IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
   6741    IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
   6742    for (int n = 0; n < ImGuiKey_COUNT; n++)
   6743        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)");
   6744
   6745    // 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)
   6746    if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
   6747        IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
   6748
   6749    // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
   6750    if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
   6751        g.IO.ConfigWindowsResizeFromEdges = false;
   6752}
   6753
   6754static void ImGui::ErrorCheckEndFrameSanityChecks()
   6755{
   6756    ImGuiContext& g = *GImGui;
   6757
   6758    // Verify that io.KeyXXX fields haven't been tampered with. Key mods shoudl not be modified between NewFrame() and EndFrame()
   6759    const ImGuiKeyModFlags expected_key_mod_flags = GetMergedKeyModFlags();
   6760    IM_ASSERT(g.IO.KeyMods == expected_key_mod_flags && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
   6761    IM_UNUSED(expected_key_mod_flags);
   6762
   6763    // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
   6764    // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
   6765    if (g.CurrentWindowStack.Size != 1)
   6766    {
   6767        if (g.CurrentWindowStack.Size > 1)
   6768        {
   6769            IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
   6770            while (g.CurrentWindowStack.Size > 1)
   6771                End();
   6772        }
   6773        else
   6774        {
   6775            IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
   6776        }
   6777    }
   6778}
   6779
   6780// Save and compare stack sizes on Begin()/End() to detect usage errors
   6781// Begin() calls this with write=true
   6782// End() calls this with write=false
   6783static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write)
   6784{
   6785    ImGuiContext& g = *GImGui;
   6786    short* p = &window->DC.StackSizesBackup[0];
   6787
   6788    // Window stacks
   6789    // 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)
   6790    { 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()
   6791    { 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()
   6792
   6793    // Global stacks
   6794    // 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.
   6795    { 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()
   6796    { 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()
   6797    { 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()
   6798    { 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()
   6799    IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
   6800}
   6801
   6802
   6803//-----------------------------------------------------------------------------
   6804// [SECTION] LAYOUT
   6805//-----------------------------------------------------------------------------
   6806// - ItemSize()
   6807// - ItemAdd()
   6808// - SameLine()
   6809// - GetCursorScreenPos()
   6810// - SetCursorScreenPos()
   6811// - GetCursorPos(), GetCursorPosX(), GetCursorPosY()
   6812// - SetCursorPos(), SetCursorPosX(), SetCursorPosY()
   6813// - GetCursorStartPos()
   6814// - Indent()
   6815// - Unindent()
   6816// - SetNextItemWidth()
   6817// - PushItemWidth()
   6818// - PushMultiItemsWidths()
   6819// - PopItemWidth()
   6820// - CalcItemWidth()
   6821// - CalcItemSize()
   6822// - GetTextLineHeight()
   6823// - GetTextLineHeightWithSpacing()
   6824// - GetFrameHeight()
   6825// - GetFrameHeightWithSpacing()
   6826// - GetContentRegionMax()
   6827// - GetContentRegionMaxAbs() [Internal]
   6828// - GetContentRegionAvail(),
   6829// - GetWindowContentRegionMin(), GetWindowContentRegionMax()
   6830// - GetWindowContentRegionWidth()
   6831// - BeginGroup()
   6832// - EndGroup()
   6833// Also see in imgui_widgets: tab bars, columns.
   6834//-----------------------------------------------------------------------------
   6835
   6836// Advance cursor given item size for layout.
   6837// Register minimum needed size so it can extend the bounding box used for auto-fit calculation.
   6838// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.
   6839void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
   6840{
   6841    ImGuiContext& g = *GImGui;
   6842    ImGuiWindow* window = g.CurrentWindow;
   6843    if (window->SkipItems)
   6844        return;
   6845
   6846    // We increase the height in this function to accommodate for baseline offset.
   6847    // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
   6848    // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
   6849    const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
   6850    const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y);
   6851
   6852    // Always align ourselves on pixel boundaries
   6853    //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]
   6854    window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
   6855    window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
   6856    window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);    // Next line
   6857    window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);        // Next line
   6858    window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
   6859    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
   6860    //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
   6861
   6862    window->DC.PrevLineSize.y = line_height;
   6863    window->DC.CurrLineSize.y = 0.0f;
   6864    window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
   6865    window->DC.CurrLineTextBaseOffset = 0.0f;
   6866
   6867    // Horizontal layout mode
   6868    if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
   6869        SameLine();
   6870}
   6871
   6872void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
   6873{
   6874    ItemSize(bb.GetSize(), text_baseline_y);
   6875}
   6876
   6877// Declare item bounding box for clipping and interaction.
   6878// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
   6879// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
   6880bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
   6881{
   6882    ImGuiContext& g = *GImGui;
   6883    ImGuiWindow* window = g.CurrentWindow;
   6884
   6885    if (id != 0)
   6886    {
   6887        // Navigation processing runs prior to clipping early-out
   6888        //  (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
   6889        //  (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
   6890        //      unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
   6891        //      thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
   6892        //      We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
   6893        //      to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
   6894        // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
   6895        // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
   6896        window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
   6897        if (g.NavId == id || g.NavAnyRequest)
   6898            if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
   6899                if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
   6900                    NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
   6901
   6902        // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
   6903#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
   6904        if (id == g.DebugItemPickerBreakId)
   6905        {
   6906            IM_DEBUG_BREAK();
   6907            g.DebugItemPickerBreakId = 0;
   6908        }
   6909#endif
   6910    }
   6911
   6912    window->DC.LastItemId = id;
   6913    window->DC.LastItemRect = bb;
   6914    window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
   6915    g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
   6916
   6917#ifdef IMGUI_ENABLE_TEST_ENGINE
   6918    if (id != 0)
   6919        IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id);
   6920#endif
   6921
   6922    // Clipping test
   6923    const bool is_clipped = IsClippedEx(bb, id, false);
   6924    if (is_clipped)
   6925        return false;
   6926    //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
   6927
   6928    // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
   6929    if (IsMouseHoveringRect(bb.Min, bb.Max))
   6930        window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
   6931    return true;
   6932}
   6933
   6934// Gets back to previous line and continue with horizontal layout
   6935//      offset_from_start_x == 0 : follow right after previous item
   6936//      offset_from_start_x != 0 : align to specified x position (relative to window/group left)
   6937//      spacing_w < 0            : use default spacing if pos_x == 0, no spacing if pos_x != 0
   6938//      spacing_w >= 0           : enforce spacing amount
   6939void ImGui::SameLine(float offset_from_start_x, float spacing_w)
   6940{
   6941    ImGuiWindow* window = GetCurrentWindow();
   6942    if (window->SkipItems)
   6943        return;
   6944
   6945    ImGuiContext& g = *GImGui;
   6946    if (offset_from_start_x != 0.0f)
   6947    {
   6948        if (spacing_w < 0.0f) spacing_w = 0.0f;
   6949        window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
   6950        window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
   6951    }
   6952    else
   6953    {
   6954        if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
   6955        window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
   6956        window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
   6957    }
   6958    window->DC.CurrLineSize = window->DC.PrevLineSize;
   6959    window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
   6960}
   6961
   6962ImVec2 ImGui::GetCursorScreenPos()
   6963{
   6964    ImGuiWindow* window = GetCurrentWindowRead();
   6965    return window->DC.CursorPos;
   6966}
   6967
   6968void ImGui::SetCursorScreenPos(const ImVec2& pos)
   6969{
   6970    ImGuiWindow* window = GetCurrentWindow();
   6971    window->DC.CursorPos = pos;
   6972    window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
   6973}
   6974
   6975// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
   6976// 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'.
   6977ImVec2 ImGui::GetCursorPos()
   6978{
   6979    ImGuiWindow* window = GetCurrentWindowRead();
   6980    return window->DC.CursorPos - window->Pos + window->Scroll;
   6981}
   6982
   6983float ImGui::GetCursorPosX()
   6984{
   6985    ImGuiWindow* window = GetCurrentWindowRead();
   6986    return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
   6987}
   6988
   6989float ImGui::GetCursorPosY()
   6990{
   6991    ImGuiWindow* window = GetCurrentWindowRead();
   6992    return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
   6993}
   6994
   6995void ImGui::SetCursorPos(const ImVec2& local_pos)
   6996{
   6997    ImGuiWindow* window = GetCurrentWindow();
   6998    window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
   6999    window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
   7000}
   7001
   7002void ImGui::SetCursorPosX(float x)
   7003{
   7004    ImGuiWindow* window = GetCurrentWindow();
   7005    window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
   7006    window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
   7007}
   7008
   7009void ImGui::SetCursorPosY(float y)
   7010{
   7011    ImGuiWindow* window = GetCurrentWindow();
   7012    window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
   7013    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
   7014}
   7015
   7016ImVec2 ImGui::GetCursorStartPos()
   7017{
   7018    ImGuiWindow* window = GetCurrentWindowRead();
   7019    return window->DC.CursorStartPos - window->Pos;
   7020}
   7021
   7022void ImGui::Indent(float indent_w)
   7023{
   7024    ImGuiContext& g = *GImGui;
   7025    ImGuiWindow* window = GetCurrentWindow();
   7026    window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
   7027    window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
   7028}
   7029
   7030void ImGui::Unindent(float indent_w)
   7031{
   7032    ImGuiContext& g = *GImGui;
   7033    ImGuiWindow* window = GetCurrentWindow();
   7034    window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
   7035    window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
   7036}
   7037
   7038// Affect large frame+labels widgets only.
   7039void ImGui::SetNextItemWidth(float item_width)
   7040{
   7041    ImGuiContext& g = *GImGui;
   7042    g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
   7043    g.NextItemData.Width = item_width;
   7044}
   7045
   7046void ImGui::PushItemWidth(float item_width)
   7047{
   7048    ImGuiContext& g = *GImGui;
   7049    ImGuiWindow* window = g.CurrentWindow;
   7050    window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
   7051    window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
   7052    g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
   7053}
   7054
   7055void ImGui::PushMultiItemsWidths(int components, float w_full)
   7056{
   7057    ImGuiContext& g = *GImGui;
   7058    ImGuiWindow* window = g.CurrentWindow;
   7059    const ImGuiStyle& style = g.Style;
   7060    const float w_item_one  = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
   7061    const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
   7062    window->DC.ItemWidthStack.push_back(w_item_last);
   7063    for (int i = 0; i < components-1; i++)
   7064        window->DC.ItemWidthStack.push_back(w_item_one);
   7065    window->DC.ItemWidth = window->DC.ItemWidthStack.back();
   7066    g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
   7067}
   7068
   7069void ImGui::PopItemWidth()
   7070{
   7071    ImGuiWindow* window = GetCurrentWindow();
   7072    window->DC.ItemWidthStack.pop_back();
   7073    window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
   7074}
   7075
   7076// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
   7077// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
   7078float ImGui::CalcItemWidth()
   7079{
   7080    ImGuiContext& g = *GImGui;
   7081    ImGuiWindow* window = g.CurrentWindow;
   7082    float w;
   7083    if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
   7084        w = g.NextItemData.Width;
   7085    else
   7086        w = window->DC.ItemWidth;
   7087    if (w < 0.0f)
   7088    {
   7089        float region_max_x = GetContentRegionMaxAbs().x;
   7090        w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
   7091    }
   7092    w = IM_FLOOR(w);
   7093    return w;
   7094}
   7095
   7096// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
   7097// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
   7098// Note that only CalcItemWidth() is publicly exposed.
   7099// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
   7100ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
   7101{
   7102    ImGuiWindow* window = GImGui->CurrentWindow;
   7103
   7104    ImVec2 region_max;
   7105    if (size.x < 0.0f || size.y < 0.0f)
   7106        region_max = GetContentRegionMaxAbs();
   7107
   7108    if (size.x == 0.0f)
   7109        size.x = default_w;
   7110    else if (size.x < 0.0f)
   7111        size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
   7112
   7113    if (size.y == 0.0f)
   7114        size.y = default_h;
   7115    else if (size.y < 0.0f)
   7116        size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
   7117
   7118    return size;
   7119}
   7120
   7121float ImGui::GetTextLineHeight()
   7122{
   7123    ImGuiContext& g = *GImGui;
   7124    return g.FontSize;
   7125}
   7126
   7127float ImGui::GetTextLineHeightWithSpacing()
   7128{
   7129    ImGuiContext& g = *GImGui;
   7130    return g.FontSize + g.Style.ItemSpacing.y;
   7131}
   7132
   7133float ImGui::GetFrameHeight()
   7134{
   7135    ImGuiContext& g = *GImGui;
   7136    return g.FontSize + g.Style.FramePadding.y * 2.0f;
   7137}
   7138
   7139float ImGui::GetFrameHeightWithSpacing()
   7140{
   7141    ImGuiContext& g = *GImGui;
   7142    return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
   7143}
   7144
   7145// 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!
   7146
   7147// FIXME: This is in window space (not screen space!).
   7148ImVec2 ImGui::GetContentRegionMax()
   7149{
   7150    ImGuiContext& g = *GImGui;
   7151    ImGuiWindow* window = g.CurrentWindow;
   7152    ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
   7153    if (window->DC.CurrentColumns)
   7154        mx.x = window->WorkRect.Max.x - window->Pos.x;
   7155    return mx;
   7156}
   7157
   7158// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
   7159ImVec2 ImGui::GetContentRegionMaxAbs()
   7160{
   7161    ImGuiContext& g = *GImGui;
   7162    ImGuiWindow* window = g.CurrentWindow;
   7163    ImVec2 mx = window->ContentRegionRect.Max;
   7164    if (window->DC.CurrentColumns)
   7165        mx.x = window->WorkRect.Max.x;
   7166    return mx;
   7167}
   7168
   7169ImVec2 ImGui::GetContentRegionAvail()
   7170{
   7171    ImGuiWindow* window = GImGui->CurrentWindow;
   7172    return GetContentRegionMaxAbs() - window->DC.CursorPos;
   7173}
   7174
   7175// In window space (not screen space!)
   7176ImVec2 ImGui::GetWindowContentRegionMin()
   7177{
   7178    ImGuiWindow* window = GImGui->CurrentWindow;
   7179    return window->ContentRegionRect.Min - window->Pos;
   7180}
   7181
   7182ImVec2 ImGui::GetWindowContentRegionMax()
   7183{
   7184    ImGuiWindow* window = GImGui->CurrentWindow;
   7185    return window->ContentRegionRect.Max - window->Pos;
   7186}
   7187
   7188float ImGui::GetWindowContentRegionWidth()
   7189{
   7190    ImGuiWindow* window = GImGui->CurrentWindow;
   7191    return window->ContentRegionRect.GetWidth();
   7192}
   7193
   7194// 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.)
   7195void ImGui::BeginGroup()
   7196{
   7197    ImGuiContext& g = *GImGui;
   7198    ImGuiWindow* window = GetCurrentWindow();
   7199
   7200    window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
   7201    ImGuiGroupData& group_data = window->DC.GroupStack.back();
   7202    group_data.BackupCursorPos = window->DC.CursorPos;
   7203    group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
   7204    group_data.BackupIndent = window->DC.Indent;
   7205    group_data.BackupGroupOffset = window->DC.GroupOffset;
   7206    group_data.BackupCurrLineSize = window->DC.CurrLineSize;
   7207    group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
   7208    group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
   7209    group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
   7210    group_data.EmitItem = true;
   7211
   7212    window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
   7213    window->DC.Indent = window->DC.GroupOffset;
   7214    window->DC.CursorMaxPos = window->DC.CursorPos;
   7215    window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
   7216    if (g.LogEnabled)
   7217        g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
   7218}
   7219
   7220void ImGui::EndGroup()
   7221{
   7222    ImGuiContext& g = *GImGui;
   7223    ImGuiWindow* window = GetCurrentWindow();
   7224    IM_ASSERT(!window->DC.GroupStack.empty());  // Mismatched BeginGroup()/EndGroup() calls
   7225
   7226    ImGuiGroupData& group_data = window->DC.GroupStack.back();
   7227
   7228    ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
   7229
   7230    window->DC.CursorPos = group_data.BackupCursorPos;
   7231    window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
   7232    window->DC.Indent = group_data.BackupIndent;
   7233    window->DC.GroupOffset = group_data.BackupGroupOffset;
   7234    window->DC.CurrLineSize = group_data.BackupCurrLineSize;
   7235    window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
   7236    if (g.LogEnabled)
   7237        g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
   7238
   7239    if (!group_data.EmitItem)
   7240    {
   7241        window->DC.GroupStack.pop_back();
   7242        return;
   7243    }
   7244
   7245    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.
   7246    ItemSize(group_bb.GetSize());
   7247    ItemAdd(group_bb, 0);
   7248
   7249    // 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.
   7250    // 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.
   7251    // Also if you grep for LastItemId you'll notice it is only used in that context.
   7252    // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
   7253    const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
   7254    const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive;
   7255    if (group_contains_curr_active_id)
   7256        window->DC.LastItemId = g.ActiveId;
   7257    else if (group_contains_prev_active_id)
   7258        window->DC.LastItemId = g.ActiveIdPreviousFrame;
   7259    window->DC.LastItemRect = group_bb;
   7260
   7261    // Forward Edited flag
   7262    if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
   7263        window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
   7264
   7265    // Forward Deactivated flag
   7266    window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
   7267    if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
   7268        window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
   7269
   7270    window->DC.GroupStack.pop_back();
   7271    //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255));   // [Debug]
   7272}
   7273
   7274
   7275//-----------------------------------------------------------------------------
   7276// [SECTION] SCROLLING
   7277//-----------------------------------------------------------------------------
   7278
   7279static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges)
   7280{
   7281    ImGuiContext& g = *GImGui;
   7282    ImVec2 scroll = window->Scroll;
   7283    if (window->ScrollTarget.x < FLT_MAX)
   7284    {
   7285        float cr_x = window->ScrollTargetCenterRatio.x;
   7286        float target_x = window->ScrollTarget.x;
   7287        if (snap_on_edges && cr_x <= 0.0f && target_x <= window->WindowPadding.x)
   7288            target_x = 0.0f;
   7289        else if (snap_on_edges && cr_x >= 1.0f && target_x >= window->ContentSize.x + window->WindowPadding.x + g.Style.ItemSpacing.x)
   7290            target_x = window->ContentSize.x + window->WindowPadding.x * 2.0f;
   7291        scroll.x = target_x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
   7292    }
   7293    if (window->ScrollTarget.y < FLT_MAX)
   7294    {
   7295        // 'snap_on_edges' allows for a discontinuity at the edge of scrolling limits to take account of WindowPadding so that scrolling to make the last item visible scroll far enough to see the padding.
   7296        float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
   7297        float cr_y = window->ScrollTargetCenterRatio.y;
   7298        float target_y = window->ScrollTarget.y;
   7299        if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y)
   7300            target_y = 0.0f;
   7301        if (snap_on_edges && cr_y >= 1.0f && target_y >= window->ContentSize.y + window->WindowPadding.y + g.Style.ItemSpacing.y)
   7302            target_y = window->ContentSize.y + window->WindowPadding.y * 2.0f;
   7303        scroll.y = target_y - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height);
   7304    }
   7305    scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f));
   7306    scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f));
   7307    if (!window->Collapsed && !window->SkipItems)
   7308    {
   7309        scroll.x = ImMin(scroll.x, window->ScrollMax.x);
   7310        scroll.y = ImMin(scroll.y, window->ScrollMax.y);
   7311    }
   7312    return scroll;
   7313}
   7314
   7315// Scroll to keep newly navigated item fully into view
   7316ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
   7317{
   7318    ImGuiContext& g = *GImGui;
   7319    ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
   7320    //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
   7321
   7322    ImVec2 delta_scroll;
   7323    if (!window_rect.Contains(item_rect))
   7324    {
   7325        if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
   7326            SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x + g.Style.ItemSpacing.x, 0.0f);
   7327        else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
   7328            SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
   7329        if (item_rect.Min.y < window_rect.Min.y)
   7330            SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
   7331        else if (item_rect.Max.y >= window_rect.Max.y)
   7332            SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
   7333
   7334        ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window, false);
   7335        delta_scroll = next_scroll - window->Scroll;
   7336    }
   7337
   7338    // Also scroll parent window to keep us into view if necessary
   7339    if (window->Flags & ImGuiWindowFlags_ChildWindow)
   7340        delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll));
   7341
   7342    return delta_scroll;
   7343}
   7344
   7345float ImGui::GetScrollX()
   7346{
   7347    ImGuiWindow* window = GImGui->CurrentWindow;
   7348    return window->Scroll.x;
   7349}
   7350
   7351float ImGui::GetScrollY()
   7352{
   7353    ImGuiWindow* window = GImGui->CurrentWindow;
   7354    return window->Scroll.y;
   7355}
   7356
   7357float ImGui::GetScrollMaxX()
   7358{
   7359    ImGuiWindow* window = GImGui->CurrentWindow;
   7360    return window->ScrollMax.x;
   7361}
   7362
   7363float ImGui::GetScrollMaxY()
   7364{
   7365    ImGuiWindow* window = GImGui->CurrentWindow;
   7366    return window->ScrollMax.y;
   7367}
   7368
   7369void ImGui::SetScrollX(float scroll_x)
   7370{
   7371    ImGuiWindow* window = GetCurrentWindow();
   7372    window->ScrollTarget.x = scroll_x;
   7373    window->ScrollTargetCenterRatio.x = 0.0f;
   7374}
   7375
   7376void ImGui::SetScrollY(float scroll_y)
   7377{
   7378    ImGuiWindow* window = GetCurrentWindow();
   7379    window->ScrollTarget.y = scroll_y;
   7380    window->ScrollTargetCenterRatio.y = 0.0f;
   7381}
   7382
   7383void ImGui::SetScrollX(ImGuiWindow* window, float new_scroll_x)
   7384{
   7385    window->ScrollTarget.x = new_scroll_x;
   7386    window->ScrollTargetCenterRatio.x = 0.0f;
   7387}
   7388
   7389void ImGui::SetScrollY(ImGuiWindow* window, float new_scroll_y)
   7390{
   7391    window->ScrollTarget.y = new_scroll_y;
   7392    window->ScrollTargetCenterRatio.y = 0.0f;
   7393}
   7394
   7395
   7396void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
   7397{
   7398    // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
   7399    IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
   7400    window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x);
   7401    window->ScrollTargetCenterRatio.x = center_x_ratio;
   7402}
   7403
   7404void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
   7405{
   7406    // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
   7407    IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
   7408    const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
   7409    local_y -= decoration_up_height;
   7410    window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y);
   7411    window->ScrollTargetCenterRatio.y = center_y_ratio;
   7412}
   7413
   7414void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
   7415{
   7416    ImGuiContext& g = *GImGui;
   7417    SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);
   7418}
   7419
   7420void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
   7421{
   7422    ImGuiContext& g = *GImGui;
   7423    SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);
   7424}
   7425
   7426// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
   7427void ImGui::SetScrollHereX(float center_x_ratio)
   7428{
   7429    ImGuiContext& g = *GImGui;
   7430    ImGuiWindow* window = g.CurrentWindow;
   7431    float target_x = window->DC.LastItemRect.Min.x - window->Pos.x; // Left of last item, in window space
   7432    float last_item_width = window->DC.LastItemRect.GetWidth();
   7433    target_x += (last_item_width * center_x_ratio) + (g.Style.ItemSpacing.x * (center_x_ratio - 0.5f) * 2.0f); // Precisely aim before, in the middle or after the last item.
   7434    SetScrollFromPosX(target_x, center_x_ratio);
   7435}
   7436
   7437// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
   7438void ImGui::SetScrollHereY(float center_y_ratio)
   7439{
   7440    ImGuiContext& g = *GImGui;
   7441    ImGuiWindow* window = g.CurrentWindow;
   7442    float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space
   7443    target_y += (window->DC.PrevLineSize.y * center_y_ratio) + (g.Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line.
   7444    SetScrollFromPosY(target_y, center_y_ratio);
   7445}
   7446
   7447//-----------------------------------------------------------------------------
   7448// [SECTION] TOOLTIPS
   7449//-----------------------------------------------------------------------------
   7450
   7451void ImGui::BeginTooltip()
   7452{
   7453    BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None);
   7454}
   7455
   7456void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags)
   7457{
   7458    ImGuiContext& g = *GImGui;
   7459
   7460    if (g.DragDropWithinSource || g.DragDropWithinTarget)
   7461    {
   7462        // 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)
   7463        // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor.
   7464        // 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.
   7465        //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;
   7466        ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale);
   7467        SetNextWindowPos(tooltip_pos);
   7468        SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f);
   7469        //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(
   7470        tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip;
   7471    }
   7472
   7473    char window_name[16];
   7474    ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
   7475    if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip)
   7476        if (ImGuiWindow* window = FindWindowByName(window_name))
   7477            if (window->Active)
   7478            {
   7479                // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
   7480                window->Hidden = true;
   7481                window->HiddenFramesCanSkipItems = 1;
   7482                ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
   7483            }
   7484    ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize;
   7485    Begin(window_name, NULL, flags | extra_flags);
   7486}
   7487
   7488void ImGui::EndTooltip()
   7489{
   7490    IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip);   // Mismatched BeginTooltip()/EndTooltip() calls
   7491    End();
   7492}
   7493
   7494void ImGui::SetTooltipV(const char* fmt, va_list args)
   7495{
   7496    BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip);
   7497    TextV(fmt, args);
   7498    EndTooltip();
   7499}
   7500
   7501void ImGui::SetTooltip(const char* fmt, ...)
   7502{
   7503    va_list args;
   7504    va_start(args, fmt);
   7505    SetTooltipV(fmt, args);
   7506    va_end(args);
   7507}
   7508
   7509//-----------------------------------------------------------------------------
   7510// [SECTION] POPUPS
   7511//-----------------------------------------------------------------------------
   7512
   7513bool ImGui::IsPopupOpen(ImGuiID id)
   7514{
   7515    ImGuiContext& g = *GImGui;
   7516    return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
   7517}
   7518
   7519bool ImGui::IsPopupOpen(const char* str_id)
   7520{
   7521    ImGuiContext& g = *GImGui;
   7522    return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
   7523}
   7524
   7525ImGuiWindow* ImGui::GetTopMostPopupModal()
   7526{
   7527    ImGuiContext& g = *GImGui;
   7528    for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
   7529        if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
   7530            if (popup->Flags & ImGuiWindowFlags_Modal)
   7531                return popup;
   7532    return NULL;
   7533}
   7534
   7535void ImGui::OpenPopup(const char* str_id)
   7536{
   7537    ImGuiContext& g = *GImGui;
   7538    OpenPopupEx(g.CurrentWindow->GetID(str_id));
   7539}
   7540
   7541// Mark popup as open (toggle toward open state).
   7542// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
   7543// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
   7544// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
   7545void ImGui::OpenPopupEx(ImGuiID id)
   7546{
   7547    ImGuiContext& g = *GImGui;
   7548    ImGuiWindow* parent_window = g.CurrentWindow;
   7549    int current_stack_size = g.BeginPopupStack.Size;
   7550    ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
   7551    popup_ref.PopupId = id;
   7552    popup_ref.Window = NULL;
   7553    popup_ref.SourceWindow = g.NavWindow;
   7554    popup_ref.OpenFrameCount = g.FrameCount;
   7555    popup_ref.OpenParentId = parent_window->IDStack.back();
   7556    popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
   7557    popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
   7558
   7559    //IMGUI_DEBUG_LOG("OpenPopupEx(0x%08X)\n", g.FrameCount, id);
   7560    if (g.OpenPopupStack.Size < current_stack_size + 1)
   7561    {
   7562        g.OpenPopupStack.push_back(popup_ref);
   7563    }
   7564    else
   7565    {
   7566        // 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
   7567        // 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
   7568        // 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.
   7569        if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
   7570        {
   7571            g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
   7572        }
   7573        else
   7574        {
   7575            // Close child popups if any, then flag popup for open/reopen
   7576            g.OpenPopupStack.resize(current_stack_size + 1);
   7577            g.OpenPopupStack[current_stack_size] = popup_ref;
   7578        }
   7579
   7580        // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
   7581        // This is equivalent to what ClosePopupToLevel() does.
   7582        //if (g.OpenPopupStack[current_stack_size].PopupId == id)
   7583        //    FocusWindow(parent_window);
   7584    }
   7585}
   7586
   7587void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
   7588{
   7589    ImGuiContext& g = *GImGui;
   7590    if (g.OpenPopupStack.empty())
   7591        return;
   7592
   7593    // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
   7594    // Don't close our own child popup windows.
   7595    int popup_count_to_keep = 0;
   7596    if (ref_window)
   7597    {
   7598        // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
   7599        for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
   7600        {
   7601            ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep];
   7602            if (!popup.Window)
   7603                continue;
   7604            IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
   7605            if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
   7606                continue;
   7607
   7608            // Trim the stack when popups are not direct descendant of the reference window (the reference window is often the NavWindow)
   7609            bool popup_or_descendent_is_ref_window = false;
   7610            for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_is_ref_window; m++)
   7611                if (ImGuiWindow* popup_window = g.OpenPopupStack[m].Window)
   7612                    if (popup_window->RootWindow == ref_window->RootWindow)
   7613                        popup_or_descendent_is_ref_window = true;
   7614            if (!popup_or_descendent_is_ref_window)
   7615                break;
   7616        }
   7617    }
   7618    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
   7619    {
   7620        //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
   7621        ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);
   7622    }
   7623}
   7624
   7625void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
   7626{
   7627    ImGuiContext& g = *GImGui;
   7628    IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
   7629    ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow;
   7630    ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;
   7631    g.OpenPopupStack.resize(remaining);
   7632
   7633    if (restore_focus_to_window_under_popup)
   7634    {
   7635        if (focus_window && !focus_window->WasActive && popup_window)
   7636        {
   7637            // Fallback
   7638            FocusTopMostWindowUnderOne(popup_window, NULL);
   7639        }
   7640        else
   7641        {
   7642            if (g.NavLayer == ImGuiNavLayer_Main && focus_window)
   7643                focus_window = NavRestoreLastChildNavWindow(focus_window);
   7644            FocusWindow(focus_window);
   7645        }
   7646    }
   7647}
   7648
   7649// Close the popup we have begin-ed into.
   7650void ImGui::CloseCurrentPopup()
   7651{
   7652    ImGuiContext& g = *GImGui;
   7653    int popup_idx = g.BeginPopupStack.Size - 1;
   7654    if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
   7655        return;
   7656
   7657    // Closing a menu closes its top-most parent popup (unless a modal)
   7658    while (popup_idx > 0)
   7659    {
   7660        ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
   7661        ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
   7662        bool close_parent = false;
   7663        if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
   7664            if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal))
   7665                close_parent = true;
   7666        if (!close_parent)
   7667            break;
   7668        popup_idx--;
   7669    }
   7670    //IMGUI_DEBUG_LOG("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
   7671    ClosePopupToLevel(popup_idx, true);
   7672
   7673    // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
   7674    // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
   7675    // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
   7676    if (ImGuiWindow* window = g.NavWindow)
   7677        window->DC.NavHideHighlightOneFrame = true;
   7678}
   7679
   7680bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
   7681{
   7682    ImGuiContext& g = *GImGui;
   7683    if (!IsPopupOpen(id))
   7684    {
   7685        g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
   7686        return false;
   7687    }
   7688
   7689    char name[20];
   7690    if (flags & ImGuiWindowFlags_ChildMenu)
   7691        ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
   7692    else
   7693        ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
   7694
   7695    flags |= ImGuiWindowFlags_Popup;
   7696    bool is_open = Begin(name, NULL, flags);
   7697    if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
   7698        EndPopup();
   7699
   7700    return is_open;
   7701}
   7702
   7703bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
   7704{
   7705    ImGuiContext& g = *GImGui;
   7706    if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
   7707    {
   7708        g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
   7709        return false;
   7710    }
   7711    flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
   7712    return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
   7713}
   7714
   7715// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
   7716// 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.
   7717bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
   7718{
   7719    ImGuiContext& g = *GImGui;
   7720    ImGuiWindow* window = g.CurrentWindow;
   7721    const ImGuiID id = window->GetID(name);
   7722    if (!IsPopupOpen(id))
   7723    {
   7724        g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
   7725        return false;
   7726    }
   7727
   7728    // Center modal windows by default
   7729    // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
   7730    if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
   7731        SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
   7732
   7733    flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings;
   7734    const bool is_open = Begin(name, p_open, flags);
   7735    if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
   7736    {
   7737        EndPopup();
   7738        if (is_open)
   7739            ClosePopupToLevel(g.BeginPopupStack.Size, true);
   7740        return false;
   7741    }
   7742    return is_open;
   7743}
   7744
   7745void ImGui::EndPopup()
   7746{
   7747    ImGuiContext& g = *GImGui;
   7748    ImGuiWindow* window = g.CurrentWindow;
   7749    IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup);  // Mismatched BeginPopup()/EndPopup() calls
   7750    IM_ASSERT(g.BeginPopupStack.Size > 0);
   7751
   7752    // Make all menus and popups wrap around for now, may need to expose that policy.
   7753    NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
   7754
   7755    // Child-popups don't need to be layed out
   7756    IM_ASSERT(g.WithinEndChild == false);
   7757    if (window->Flags & ImGuiWindowFlags_ChildWindow)
   7758        g.WithinEndChild = true;
   7759    End();
   7760    g.WithinEndChild = false;
   7761}
   7762
   7763bool ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiMouseButton mouse_button)
   7764{
   7765    ImGuiWindow* window = GImGui->CurrentWindow;
   7766    if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
   7767    {
   7768        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!
   7769        IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
   7770        OpenPopupEx(id);
   7771        return true;
   7772    }
   7773    return false;
   7774}
   7775
   7776// This is a helper to handle the simplest case of associating one named popup to one given widget.
   7777// You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
   7778// You can pass a NULL str_id to use the identifier of the last item.
   7779bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiMouseButton mouse_button)
   7780{
   7781    ImGuiWindow* window = GImGui->CurrentWindow;
   7782    if (window->SkipItems)
   7783        return false;
   7784    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!
   7785    IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
   7786    if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
   7787        OpenPopupEx(id);
   7788    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
   7789}
   7790
   7791bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mouse_button, bool also_over_items)
   7792{
   7793    if (!str_id)
   7794        str_id = "window_context";
   7795    ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
   7796    if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
   7797        if (also_over_items || !IsAnyItemHovered())
   7798            OpenPopupEx(id);
   7799    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
   7800}
   7801
   7802bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiMouseButton mouse_button)
   7803{
   7804    if (!str_id)
   7805        str_id = "void_context";
   7806    ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
   7807    if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
   7808        OpenPopupEx(id);
   7809    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
   7810}
   7811
   7812// 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.)
   7813// 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.
   7814ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)
   7815{
   7816    ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
   7817    //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
   7818    //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
   7819
   7820    // Combo Box policy (we want a connecting edge)
   7821    if (policy == ImGuiPopupPositionPolicy_ComboBox)
   7822    {
   7823        const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };
   7824        for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
   7825        {
   7826            const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
   7827            if (n != -1 && dir == *last_dir) // Already tried this direction?
   7828                continue;
   7829            ImVec2 pos;
   7830            if (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default)
   7831            if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
   7832            if (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
   7833            if (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
   7834            if (!r_outer.Contains(ImRect(pos, pos + size)))
   7835                continue;
   7836            *last_dir = dir;
   7837            return pos;
   7838        }
   7839    }
   7840
   7841    // Default popup policy
   7842    const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
   7843    for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
   7844    {
   7845        const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
   7846        if (n != -1 && dir == *last_dir) // Already tried this direction?
   7847            continue;
   7848        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);
   7849        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);
   7850        if (avail_w < size.x || avail_h < size.y)
   7851            continue;
   7852        ImVec2 pos;
   7853        pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
   7854        pos.y = (dir == ImGuiDir_Up)   ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down)  ? r_avoid.Max.y : base_pos_clamped.y;
   7855        *last_dir = dir;
   7856        return pos;
   7857    }
   7858
   7859    // Fallback, try to keep within display
   7860    *last_dir = ImGuiDir_None;
   7861    ImVec2 pos = ref_pos;
   7862    pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
   7863    pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
   7864    return pos;
   7865}
   7866
   7867ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
   7868{
   7869    IM_UNUSED(window);
   7870    ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding;
   7871    ImRect r_screen = GetViewportRect();
   7872    r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
   7873    return r_screen;
   7874}
   7875
   7876ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
   7877{
   7878    ImGuiContext& g = *GImGui;
   7879
   7880    ImRect r_outer = GetWindowAllowedExtentRect(window);
   7881    if (window->Flags & ImGuiWindowFlags_ChildMenu)
   7882    {
   7883        // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
   7884        // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
   7885        IM_ASSERT(g.CurrentWindow == window);
   7886        ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
   7887        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).
   7888        ImRect r_avoid;
   7889        if (parent_window->DC.MenuBarAppending)
   7890            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
   7891        else
   7892            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);
   7893        return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
   7894    }
   7895    if (window->Flags & ImGuiWindowFlags_Popup)
   7896    {
   7897        ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
   7898        return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
   7899    }
   7900    if (window->Flags & ImGuiWindowFlags_Tooltip)
   7901    {
   7902        // Position tooltip (always follows mouse)
   7903        float sc = g.Style.MouseCursorScale;
   7904        ImVec2 ref_pos = NavCalcPreferredRefPos();
   7905        ImRect r_avoid;
   7906        if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))
   7907            r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
   7908        else
   7909            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.
   7910        ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
   7911        if (window->AutoPosLastDirection == ImGuiDir_None)
   7912            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.
   7913        return pos;
   7914    }
   7915    IM_ASSERT(0);
   7916    return window->Pos;
   7917}
   7918
   7919//-----------------------------------------------------------------------------
   7920// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
   7921//-----------------------------------------------------------------------------
   7922
   7923// FIXME-NAV: The existence of SetNavID vs SetNavIDWithRectRel vs SetFocusID is incredibly messy and confusing,
   7924// and needs some explanation or serious refactoring.
   7925void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id)
   7926{
   7927    ImGuiContext& g = *GImGui;
   7928    IM_ASSERT(g.NavWindow);
   7929    IM_ASSERT(nav_layer == 0 || nav_layer == 1);
   7930    g.NavId = id;
   7931    g.NavFocusScopeId = focus_scope_id;
   7932    g.NavWindow->NavLastIds[nav_layer] = id;
   7933}
   7934
   7935void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
   7936{
   7937    ImGuiContext& g = *GImGui;
   7938    SetNavID(id, nav_layer, focus_scope_id);
   7939    g.NavWindow->NavRectRel[nav_layer] = rect_rel;
   7940    g.NavMousePosDirty = true;
   7941    g.NavDisableHighlight = false;
   7942    g.NavDisableMouseHover = true;
   7943}
   7944
   7945void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
   7946{
   7947    ImGuiContext& g = *GImGui;
   7948    IM_ASSERT(id != 0);
   7949
   7950    // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid.
   7951    // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)
   7952    const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
   7953    if (g.NavWindow != window)
   7954        g.NavInitRequest = false;
   7955    g.NavWindow = window;
   7956    g.NavId = id;
   7957    g.NavLayer = nav_layer;
   7958    g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
   7959    window->NavLastIds[nav_layer] = id;
   7960    if (window->DC.LastItemId == id)
   7961        window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
   7962
   7963    if (g.ActiveIdSource == ImGuiInputSource_Nav)
   7964        g.NavDisableMouseHover = true;
   7965    else
   7966        g.NavDisableHighlight = true;
   7967}
   7968
   7969ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
   7970{
   7971    if (ImFabs(dx) > ImFabs(dy))
   7972        return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
   7973    return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
   7974}
   7975
   7976static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
   7977{
   7978    if (a1 < b0)
   7979        return a1 - b0;
   7980    if (b1 < a0)
   7981        return a0 - b1;
   7982    return 0.0f;
   7983}
   7984
   7985static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
   7986{
   7987    if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
   7988    {
   7989        r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
   7990        r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
   7991    }
   7992    else
   7993    {
   7994        r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
   7995        r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
   7996    }
   7997}
   7998
   7999// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
   8000static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
   8001{
   8002    ImGuiContext& g = *GImGui;
   8003    ImGuiWindow* window = g.CurrentWindow;
   8004    if (g.NavLayer != window->DC.NavLayerCurrent)
   8005        return false;
   8006
   8007    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)
   8008    g.NavScoringCount++;
   8009
   8010    // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
   8011    if (window->ParentWindow == g.NavWindow)
   8012    {
   8013        IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
   8014        if (!window->ClipRect.Overlaps(cand))
   8015            return false;
   8016        cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
   8017    }
   8018
   8019    // 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)
   8020    // For example, this ensure that items in one column are not reached when moving vertically from items in another column.
   8021    NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect);
   8022
   8023    // Compute distance between boxes
   8024    // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
   8025    float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
   8026    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
   8027    if (dby != 0.0f && dbx != 0.0f)
   8028       dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
   8029    float dist_box = ImFabs(dbx) + ImFabs(dby);
   8030
   8031    // 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)
   8032    float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
   8033    float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
   8034    float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
   8035
   8036    // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
   8037    ImGuiDir quadrant;
   8038    float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
   8039    if (dbx != 0.0f || dby != 0.0f)
   8040    {
   8041        // For non-overlapping boxes, use distance between boxes
   8042        dax = dbx;
   8043        day = dby;
   8044        dist_axial = dist_box;
   8045        quadrant = ImGetDirQuadrantFromDelta(dbx, dby);
   8046    }
   8047    else if (dcx != 0.0f || dcy != 0.0f)
   8048    {
   8049        // For overlapping boxes with different centers, use distance between centers
   8050        dax = dcx;
   8051        day = dcy;
   8052        dist_axial = dist_center;
   8053        quadrant = ImGetDirQuadrantFromDelta(dcx, dcy);
   8054    }
   8055    else
   8056    {
   8057        // 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)
   8058        quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
   8059    }
   8060
   8061#if IMGUI_DEBUG_NAV_SCORING
   8062    char buf[128];
   8063    if (IsMouseHoveringRect(cand.Min, cand.Max))
   8064    {
   8065        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]);
   8066        ImDrawList* draw_list = GetForegroundDrawList(window);
   8067        draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
   8068        draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
   8069        draw_list->AddRectFilled(cand.Max - ImVec2(4,4), cand.Max + CalcTextSize(buf) + ImVec2(4,4), IM_COL32(40,0,0,150));
   8070        draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
   8071    }
   8072    else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
   8073    {
   8074        if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
   8075        if (quadrant == g.NavMoveDir)
   8076        {
   8077            ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
   8078            ImDrawList* draw_list = GetForegroundDrawList(window);
   8079            draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
   8080            draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
   8081        }
   8082    }
   8083 #endif
   8084
   8085    // Is it in the quadrant we're interesting in moving to?
   8086    bool new_best = false;
   8087    if (quadrant == g.NavMoveDir)
   8088    {
   8089        // Does it beat the current best candidate?
   8090        if (dist_box < result->DistBox)
   8091        {
   8092            result->DistBox = dist_box;
   8093            result->DistCenter = dist_center;
   8094            return true;
   8095        }
   8096        if (dist_box == result->DistBox)
   8097        {
   8098            // Try using distance between center points to break ties
   8099            if (dist_center < result->DistCenter)
   8100            {
   8101                result->DistCenter = dist_center;
   8102                new_best = true;
   8103            }
   8104            else if (dist_center == result->DistCenter)
   8105            {
   8106                // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
   8107                // (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),
   8108                // 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.
   8109                if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
   8110                    new_best = true;
   8111            }
   8112        }
   8113    }
   8114
   8115    // 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
   8116    // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
   8117    // 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.
   8118    // 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.
   8119    // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
   8120    if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)  // Check axial match
   8121        if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
   8122            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))
   8123            {
   8124                result->DistAxial = dist_axial;
   8125                new_best = true;
   8126            }
   8127
   8128    return new_best;
   8129}
   8130
   8131// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
   8132static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
   8133{
   8134    ImGuiContext& g = *GImGui;
   8135    //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.
   8136    //    return;
   8137
   8138    const ImGuiItemFlags item_flags = window->DC.ItemFlags;
   8139    const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
   8140
   8141    // Process Init Request
   8142    if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
   8143    {
   8144        // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
   8145        if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
   8146        {
   8147            g.NavInitResultId = id;
   8148            g.NavInitResultRectRel = nav_bb_rel;
   8149        }
   8150        if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
   8151        {
   8152            g.NavInitRequest = false; // Found a match, clear request
   8153            NavUpdateAnyRequestFlag();
   8154        }
   8155    }
   8156
   8157    // Process Move Request (scoring for navigation)
   8158    // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
   8159    if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled|ImGuiItemFlags_NoNav)))
   8160    {
   8161        ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
   8162#if IMGUI_DEBUG_NAV_SCORING
   8163        // [DEBUG] Score all items in NavWindow at all times
   8164        if (!g.NavMoveRequest)
   8165            g.NavMoveDir = g.NavMoveDirLast;
   8166        bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
   8167#else
   8168        bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
   8169#endif
   8170        if (new_best)
   8171        {
   8172            result->Window = window;
   8173            result->ID = id;
   8174            result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
   8175            result->RectRel = nav_bb_rel;
   8176        }
   8177
   8178        // Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
   8179        const float VISIBLE_RATIO = 0.70f;
   8180        if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
   8181            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)
   8182                if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb))
   8183                {
   8184                    result = &g.NavMoveResultLocalVisibleSet;
   8185                    result->Window = window;
   8186                    result->ID = id;
   8187                    result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
   8188                    result->RectRel = nav_bb_rel;
   8189                }
   8190    }
   8191
   8192    // Update window-relative bounding box of navigated item
   8193    if (g.NavId == id)
   8194    {
   8195        g.NavWindow = window;                                           // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
   8196        g.NavLayer = window->DC.NavLayerCurrent;
   8197        g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
   8198        g.NavIdIsAlive = true;
   8199        g.NavIdTabCounter = window->DC.FocusCounterTabStop;
   8200        window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel;    // Store item bounding box (relative to window position)
   8201    }
   8202}
   8203
   8204bool ImGui::NavMoveRequestButNoResultYet()
   8205{
   8206    ImGuiContext& g = *GImGui;
   8207    return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
   8208}
   8209
   8210void ImGui::NavMoveRequestCancel()
   8211{
   8212    ImGuiContext& g = *GImGui;
   8213    g.NavMoveRequest = false;
   8214    NavUpdateAnyRequestFlag();
   8215}
   8216
   8217void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags)
   8218{
   8219    ImGuiContext& g = *GImGui;
   8220    IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
   8221    NavMoveRequestCancel();
   8222    g.NavMoveDir = move_dir;
   8223    g.NavMoveClipDir = clip_dir;
   8224    g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
   8225    g.NavMoveRequestFlags = move_flags;
   8226    g.NavWindow->NavRectRel[g.NavLayer] = bb_rel;
   8227}
   8228
   8229void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags)
   8230{
   8231    ImGuiContext& g = *GImGui;
   8232    if (g.NavWindow != window || !NavMoveRequestButNoResultYet() || g.NavMoveRequestForward != ImGuiNavForward_None || g.NavLayer != ImGuiNavLayer_Main)
   8233        return;
   8234    IM_ASSERT(move_flags != 0); // No points calling this with no wrapping
   8235    ImRect bb_rel = window->NavRectRel[0];
   8236
   8237    ImGuiDir clip_dir = g.NavMoveDir;
   8238    if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
   8239    {
   8240        bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x;
   8241        if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; }
   8242        NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
   8243    }
   8244    if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
   8245    {
   8246        bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x;
   8247        if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(+bb_rel.GetHeight()); clip_dir = ImGuiDir_Down; }
   8248        NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
   8249    }
   8250    if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
   8251    {
   8252        bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y;
   8253        if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; }
   8254        NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
   8255    }
   8256    if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
   8257    {
   8258        bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y;
   8259        if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(+bb_rel.GetWidth()); clip_dir = ImGuiDir_Right; }
   8260        NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
   8261    }
   8262}
   8263
   8264// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
   8265// This way we could find the last focused window among our children. It would be much less confusing this way?
   8266static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window)
   8267{
   8268    ImGuiWindow* parent_window = nav_window;
   8269    while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
   8270        parent_window = parent_window->ParentWindow;
   8271    if (parent_window && parent_window != nav_window)
   8272        parent_window->NavLastChildNavWindow = nav_window;
   8273}
   8274
   8275// Restore the last focused child.
   8276// Call when we are expected to land on the Main Layer (0) after FocusWindow()
   8277static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)
   8278{
   8279    return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window;
   8280}
   8281
   8282static void NavRestoreLayer(ImGuiNavLayer layer)
   8283{
   8284    ImGuiContext& g = *GImGui;
   8285    g.NavLayer = layer;
   8286    if (layer == 0)
   8287        g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow);
   8288    ImGuiWindow* window = g.NavWindow;
   8289    if (layer == 0 && window->NavLastIds[0] != 0)
   8290        ImGui::SetNavIDWithRectRel(window->NavLastIds[0], layer, 0, window->NavRectRel[0]);
   8291    else
   8292        ImGui::NavInitWindow(window, true);
   8293}
   8294
   8295static inline void ImGui::NavUpdateAnyRequestFlag()
   8296{
   8297    ImGuiContext& g = *GImGui;
   8298    g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
   8299    if (g.NavAnyRequest)
   8300        IM_ASSERT(g.NavWindow != NULL);
   8301}
   8302
   8303// This needs to be called before we submit any widget (aka in or before Begin)
   8304void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
   8305{
   8306    ImGuiContext& g = *GImGui;
   8307    IM_ASSERT(window == g.NavWindow);
   8308    bool init_for_nav = false;
   8309    if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
   8310        if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
   8311            init_for_nav = true;
   8312    //IMGUI_DEBUG_LOG("[Nav] NavInitWindow() init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
   8313    if (init_for_nav)
   8314    {
   8315        SetNavID(0, g.NavLayer, 0);
   8316        g.NavInitRequest = true;
   8317        g.NavInitRequestFromMove = false;
   8318        g.NavInitResultId = 0;
   8319        g.NavInitResultRectRel = ImRect();
   8320        NavUpdateAnyRequestFlag();
   8321    }
   8322    else
   8323    {
   8324        g.NavId = window->NavLastIds[0];
   8325        g.NavFocusScopeId = 0;
   8326    }
   8327}
   8328
   8329static ImVec2 ImGui::NavCalcPreferredRefPos()
   8330{
   8331    ImGuiContext& g = *GImGui;
   8332    if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow)
   8333    {
   8334        // Mouse (we need a fallback in case the mouse becomes invalid after being used)
   8335        if (IsMousePosValid(&g.IO.MousePos))
   8336            return g.IO.MousePos;
   8337        return g.LastValidMousePos;
   8338    }
   8339    else
   8340    {
   8341        // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item.
   8342        const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
   8343        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()));
   8344        ImRect visible_rect = GetViewportRect();
   8345        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.
   8346    }
   8347}
   8348
   8349float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
   8350{
   8351    ImGuiContext& g = *GImGui;
   8352    if (mode == ImGuiInputReadMode_Down)
   8353        return g.IO.NavInputs[n];                         // Instant, read analog input (0.0f..1.0f, as provided by user)
   8354
   8355    const float t = g.IO.NavInputsDownDuration[n];
   8356    if (t < 0.0f && mode == ImGuiInputReadMode_Released)  // Return 1.0f when just released, no repeat, ignore analog input.
   8357        return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
   8358    if (t < 0.0f)
   8359        return 0.0f;
   8360    if (mode == ImGuiInputReadMode_Pressed)               // Return 1.0f when just pressed, no repeat, ignore analog input.
   8361        return (t == 0.0f) ? 1.0f : 0.0f;
   8362    if (mode == ImGuiInputReadMode_Repeat)
   8363        return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f);
   8364    if (mode == ImGuiInputReadMode_RepeatSlow)
   8365        return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f);
   8366    if (mode == ImGuiInputReadMode_RepeatFast)
   8367        return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f);
   8368    return 0.0f;
   8369}
   8370
   8371ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
   8372{
   8373    ImVec2 delta(0.0f, 0.0f);
   8374    if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
   8375        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode)   - GetNavInputAmount(ImGuiNavInput_KeyLeft_,   mode), GetNavInputAmount(ImGuiNavInput_KeyDown_,   mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_,   mode));
   8376    if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
   8377        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode)   - GetNavInputAmount(ImGuiNavInput_DpadLeft,   mode), GetNavInputAmount(ImGuiNavInput_DpadDown,   mode) - GetNavInputAmount(ImGuiNavInput_DpadUp,   mode));
   8378    if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
   8379        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
   8380    if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
   8381        delta *= slow_factor;
   8382    if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
   8383        delta *= fast_factor;
   8384    return delta;
   8385}
   8386
   8387static void ImGui::NavUpdate()
   8388{
   8389    ImGuiContext& g = *GImGui;
   8390    g.IO.WantSetMousePos = false;
   8391#if 0
   8392    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);
   8393#endif
   8394
   8395    // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
   8396    // (do it before we map Keyboard input!)
   8397    bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
   8398    bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
   8399    if (nav_gamepad_active)
   8400        if (g.IO.NavInputs[ImGuiNavInput_Activate] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Input] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Cancel] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Menu] > 0.0f)
   8401            g.NavInputSource = ImGuiInputSource_NavGamepad;
   8402
   8403    // Update Keyboard->Nav inputs mapping
   8404    if (nav_keyboard_active)
   8405    {
   8406        #define NAV_MAP_KEY(_KEY, _NAV_INPUT)  do { if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0)
   8407        NAV_MAP_KEY(ImGuiKey_Space,     ImGuiNavInput_Activate );
   8408        NAV_MAP_KEY(ImGuiKey_Enter,     ImGuiNavInput_Input    );
   8409        NAV_MAP_KEY(ImGuiKey_Escape,    ImGuiNavInput_Cancel   );
   8410        NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
   8411        NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
   8412        NAV_MAP_KEY(ImGuiKey_UpArrow,   ImGuiNavInput_KeyUp_   );
   8413        NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
   8414        if (g.IO.KeyCtrl)
   8415            g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
   8416        if (g.IO.KeyShift)
   8417            g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
   8418        if (g.IO.KeyAlt && !g.IO.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu.
   8419            g.IO.NavInputs[ImGuiNavInput_KeyMenu_]  = 1.0f;
   8420        #undef NAV_MAP_KEY
   8421    }
   8422    memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration));
   8423    for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++)
   8424        g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
   8425
   8426    // Process navigation init request (select first/default focus)
   8427    // 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)
   8428    if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove) && g.NavWindow)
   8429    {
   8430        // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
   8431        //IMGUI_DEBUG_LOG("[Nav] Apply NavInitRequest result: 0x%08X Layer %d in \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
   8432        if (g.NavInitRequestFromMove)
   8433            SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
   8434        else
   8435            SetNavID(g.NavInitResultId, g.NavLayer, 0);
   8436        g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
   8437    }
   8438    g.NavInitRequest = false;
   8439    g.NavInitRequestFromMove = false;
   8440    g.NavInitResultId = 0;
   8441    g.NavJustMovedToId = 0;
   8442
   8443    // Process navigation move request
   8444    if (g.NavMoveRequest)
   8445        NavUpdateMoveResult();
   8446
   8447    // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
   8448    if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
   8449    {
   8450        IM_ASSERT(g.NavMoveRequest);
   8451        if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
   8452            g.NavDisableHighlight = false;
   8453        g.NavMoveRequestForward = ImGuiNavForward_None;
   8454    }
   8455
   8456    // Apply application mouse position movement, after we had a chance to process move request result.
   8457    if (g.NavMousePosDirty && g.NavIdIsAlive)
   8458    {
   8459        // Set mouse position given our knowledge of the navigated item position from last frame
   8460        if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
   8461        {
   8462            if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
   8463            {
   8464                g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos();
   8465                g.IO.WantSetMousePos = true;
   8466            }
   8467        }
   8468        g.NavMousePosDirty = false;
   8469    }
   8470    g.NavIdIsAlive = false;
   8471    g.NavJustTabbedId = 0;
   8472    IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
   8473
   8474    // 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
   8475    if (g.NavWindow)
   8476        NavSaveLastChildNavWindowIntoParent(g.NavWindow);
   8477    if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main)
   8478        g.NavWindow->NavLastChildNavWindow = NULL;
   8479
   8480    // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
   8481    NavUpdateWindowing();
   8482
   8483    // Set output flags for user application
   8484    g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
   8485    g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
   8486
   8487    // Process NavCancel input (to close a popup, get back to parent, clear focus)
   8488    if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
   8489    {
   8490        if (g.ActiveId != 0)
   8491        {
   8492            if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
   8493                ClearActiveID();
   8494        }
   8495        else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
   8496        {
   8497            // Exit child window
   8498            ImGuiWindow* child_window = g.NavWindow;
   8499            ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
   8500            IM_ASSERT(child_window->ChildId != 0);
   8501            FocusWindow(parent_window);
   8502            SetNavID(child_window->ChildId, 0, 0);
   8503            // Reassigning with same value, we're being explicit here.
   8504            g.NavIdIsAlive = false;     // -V1048
   8505            if (g.NavDisableMouseHover)
   8506                g.NavMousePosDirty = true;
   8507        }
   8508        else if (g.OpenPopupStack.Size > 0)
   8509        {
   8510            // Close open popup/menu
   8511            if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
   8512                ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
   8513        }
   8514        else if (g.NavLayer != ImGuiNavLayer_Main)
   8515        {
   8516            // Leave the "menu" layer
   8517            NavRestoreLayer(ImGuiNavLayer_Main);
   8518        }
   8519        else
   8520        {
   8521            // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
   8522            if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
   8523                g.NavWindow->NavLastIds[0] = 0;
   8524            g.NavId = g.NavFocusScopeId = 0;
   8525        }
   8526    }
   8527
   8528    // Process manual activation request
   8529    g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
   8530    if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
   8531    {
   8532        bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
   8533        bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
   8534        if (g.ActiveId == 0 && activate_pressed)
   8535            g.NavActivateId = g.NavId;
   8536        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
   8537            g.NavActivateDownId = g.NavId;
   8538        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
   8539            g.NavActivatePressedId = g.NavId;
   8540        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
   8541            g.NavInputId = g.NavId;
   8542    }
   8543    if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
   8544        g.NavDisableHighlight = true;
   8545    if (g.NavActivateId != 0)
   8546        IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
   8547    g.NavMoveRequest = false;
   8548
   8549    // Process programmatic activation request
   8550    if (g.NavNextActivateId != 0)
   8551        g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
   8552    g.NavNextActivateId = 0;
   8553
   8554    // Initiate directional inputs request
   8555    if (g.NavMoveRequestForward == ImGuiNavForward_None)
   8556    {
   8557        g.NavMoveDir = ImGuiDir_None;
   8558        g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
   8559        if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
   8560        {
   8561            const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
   8562            if (!IsActiveIdUsingNavDir(ImGuiDir_Left)  && (IsNavInputTest(ImGuiNavInput_DpadLeft,  read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_,  read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
   8563            if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
   8564            if (!IsActiveIdUsingNavDir(ImGuiDir_Up)    && (IsNavInputTest(ImGuiNavInput_DpadUp,    read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_,    read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
   8565            if (!IsActiveIdUsingNavDir(ImGuiDir_Down)  && (IsNavInputTest(ImGuiNavInput_DpadDown,  read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_,  read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
   8566        }
   8567        g.NavMoveClipDir = g.NavMoveDir;
   8568    }
   8569    else
   8570    {
   8571        // 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)
   8572        // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
   8573        IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
   8574        IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
   8575        g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
   8576    }
   8577
   8578    // Update PageUp/PageDown/Home/End scroll
   8579    // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
   8580    float nav_scoring_rect_offset_y = 0.0f;
   8581    if (nav_keyboard_active)
   8582        nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
   8583
   8584    // 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
   8585    if (g.NavMoveDir != ImGuiDir_None)
   8586    {
   8587        g.NavMoveRequest = true;
   8588        g.NavMoveRequestKeyMods = g.IO.KeyMods;
   8589        g.NavMoveDirLast = g.NavMoveDir;
   8590    }
   8591    if (g.NavMoveRequest && g.NavId == 0)
   8592    {
   8593        //IMGUI_DEBUG_LOG("[Nav] NavInitRequest from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
   8594        g.NavInitRequest = g.NavInitRequestFromMove = true;
   8595        // Reassigning with same value, we're being explicit here.
   8596        g.NavInitResultId = 0;     // -V1048
   8597        g.NavDisableHighlight = false;
   8598    }
   8599    NavUpdateAnyRequestFlag();
   8600
   8601    // Scrolling
   8602    if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
   8603    {
   8604        // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
   8605        ImGuiWindow* window = g.NavWindow;
   8606        const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * g.IO.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
   8607        if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
   8608        {
   8609            if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
   8610                SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
   8611            if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
   8612                SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
   8613        }
   8614
   8615        // *Normal* Manual scroll with NavScrollXXX keys
   8616        // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
   8617        ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f);
   8618        if (scroll_dir.x != 0.0f && window->ScrollbarX)
   8619        {
   8620            SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
   8621            g.NavMoveFromClampedRefRect = true;
   8622        }
   8623        if (scroll_dir.y != 0.0f)
   8624        {
   8625            SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
   8626            g.NavMoveFromClampedRefRect = true;
   8627        }
   8628    }
   8629
   8630    // Reset search results
   8631    g.NavMoveResultLocal.Clear();
   8632    g.NavMoveResultLocalVisibleSet.Clear();
   8633    g.NavMoveResultOther.Clear();
   8634
   8635    // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
   8636    if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == ImGuiNavLayer_Main)
   8637    {
   8638        ImGuiWindow* window = g.NavWindow;
   8639        ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1,1), window->InnerRect.Max - window->Pos + ImVec2(1,1));
   8640        if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
   8641        {
   8642            float pad = window->CalcFontSize() * 0.5f;
   8643            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
   8644            window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel);
   8645            g.NavId = g.NavFocusScopeId = 0;
   8646        }
   8647        g.NavMoveFromClampedRefRect = false;
   8648    }
   8649
   8650    // 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)
   8651    ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0);
   8652    g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect();
   8653    g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
   8654    g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
   8655    g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
   8656    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().
   8657    //GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
   8658    g.NavScoringCount = 0;
   8659#if IMGUI_DEBUG_NAV_RECTS
   8660    if (g.NavWindow)
   8661    {
   8662        ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow);
   8663        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]
   8664        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); }
   8665    }
   8666#endif
   8667}
   8668
   8669// Apply result from previous frame navigation directional move request
   8670static void ImGui::NavUpdateMoveResult()
   8671{
   8672    ImGuiContext& g = *GImGui;
   8673    if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
   8674    {
   8675        // 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)
   8676        if (g.NavId != 0)
   8677        {
   8678            g.NavDisableHighlight = false;
   8679            g.NavDisableMouseHover = true;
   8680        }
   8681        return;
   8682    }
   8683
   8684    // Select which result to use
   8685    ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
   8686
   8687    // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
   8688    if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
   8689        if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId)
   8690            result = &g.NavMoveResultLocalVisibleSet;
   8691
   8692    // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
   8693    if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)
   8694        if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter))
   8695            result = &g.NavMoveResultOther;
   8696    IM_ASSERT(g.NavWindow && result->Window);
   8697
   8698    // Scroll to keep newly navigated item fully into view.
   8699    if (g.NavLayer == ImGuiNavLayer_Main)
   8700    {
   8701        ImVec2 delta_scroll;
   8702        if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge)
   8703        {
   8704            float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
   8705            delta_scroll.y = result->Window->Scroll.y - scroll_target;
   8706            SetScrollY(result->Window, scroll_target);
   8707        }
   8708        else
   8709        {
   8710            ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
   8711            delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
   8712        }
   8713
   8714        // Offset our result position so mouse position can be applied immediately after in NavUpdate()
   8715        result->RectRel.TranslateX(-delta_scroll.x);
   8716        result->RectRel.TranslateY(-delta_scroll.y);
   8717    }
   8718
   8719    ClearActiveID();
   8720    g.NavWindow = result->Window;
   8721    if (g.NavId != result->ID)
   8722    {
   8723        // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
   8724        g.NavJustMovedToId = result->ID;
   8725        g.NavJustMovedToFocusScopeId = result->FocusScopeId;
   8726        g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods;
   8727    }
   8728    SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
   8729    g.NavMoveFromClampedRefRect = false;
   8730}
   8731
   8732// Handle PageUp/PageDown/Home/End keys
   8733static float ImGui::NavUpdatePageUpPageDown()
   8734{
   8735    ImGuiContext& g = *GImGui;
   8736    if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL)
   8737        return 0.0f;
   8738    if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main)
   8739        return 0.0f;
   8740
   8741    ImGuiWindow* window = g.NavWindow;
   8742    const bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
   8743    const bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
   8744    const bool home_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
   8745    const bool end_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
   8746    if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
   8747    {
   8748        if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
   8749        {
   8750            // Fallback manual-scroll when window has no navigable item
   8751            if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
   8752                SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
   8753            else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
   8754                SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
   8755            else if (home_pressed)
   8756                SetScrollY(window, 0.0f);
   8757            else if (end_pressed)
   8758                SetScrollY(window, window->ScrollMax.y);
   8759        }
   8760        else
   8761        {
   8762            ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
   8763            const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
   8764            float nav_scoring_rect_offset_y = 0.0f;
   8765            if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
   8766            {
   8767                nav_scoring_rect_offset_y = -page_offset_y;
   8768                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)
   8769                g.NavMoveClipDir = ImGuiDir_Up;
   8770                g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
   8771            }
   8772            else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
   8773            {
   8774                nav_scoring_rect_offset_y = +page_offset_y;
   8775                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)
   8776                g.NavMoveClipDir = ImGuiDir_Down;
   8777                g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
   8778            }
   8779            else if (home_pressed)
   8780            {
   8781                // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
   8782                // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
   8783                // Preserve current horizontal position if we have any.
   8784                nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
   8785                if (nav_rect_rel.IsInverted())
   8786                    nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
   8787                g.NavMoveDir = ImGuiDir_Down;
   8788                g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
   8789            }
   8790            else if (end_pressed)
   8791            {
   8792                nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
   8793                if (nav_rect_rel.IsInverted())
   8794                    nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
   8795                g.NavMoveDir = ImGuiDir_Up;
   8796                g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
   8797            }
   8798            return nav_scoring_rect_offset_y;
   8799        }
   8800    }
   8801    return 0.0f;
   8802}
   8803
   8804static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N)
   8805{
   8806    ImGuiContext& g = *GImGui;
   8807    for (int i = g.WindowsFocusOrder.Size-1; i >= 0; i--)
   8808        if (g.WindowsFocusOrder[i] == window)
   8809            return i;
   8810    return -1;
   8811}
   8812
   8813static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
   8814{
   8815    ImGuiContext& g = *GImGui;
   8816    for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)
   8817        if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i]))
   8818            return g.WindowsFocusOrder[i];
   8819    return NULL;
   8820}
   8821
   8822static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
   8823{
   8824    ImGuiContext& g = *GImGui;
   8825    IM_ASSERT(g.NavWindowingTarget);
   8826    if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
   8827        return;
   8828
   8829    const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget);
   8830    ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
   8831    if (!window_target)
   8832        window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);
   8833    if (window_target) // Don't reset windowing target if there's a single window in the list
   8834        g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
   8835    g.NavWindowingToggleLayer = false;
   8836}
   8837
   8838// Windowing management mode
   8839// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer)
   8840// Gamepad:  Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer)
   8841static void ImGui::NavUpdateWindowing()
   8842{
   8843    ImGuiContext& g = *GImGui;
   8844    ImGuiWindow* apply_focus_window = NULL;
   8845    bool apply_toggle_layer = false;
   8846
   8847    ImGuiWindow* modal_window = GetTopMostPopupModal();
   8848    if (modal_window != NULL)
   8849    {
   8850        g.NavWindowingTarget = NULL;
   8851        return;
   8852    }
   8853
   8854    // Fade out
   8855    if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
   8856    {
   8857        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f);
   8858        if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
   8859            g.NavWindowingTargetAnim = NULL;
   8860    }
   8861
   8862    // Start CTRL-TAB or Square+L/R window selection
   8863    bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
   8864    bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
   8865    if (start_windowing_with_gamepad || start_windowing_with_keyboard)
   8866        if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
   8867        {
   8868            g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // FIXME-DOCK: Will need to use RootWindowDockStop
   8869            g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
   8870            g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
   8871            g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
   8872        }
   8873
   8874    // Gamepad update
   8875    g.NavWindowingTimer += g.IO.DeltaTime;
   8876    if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad)
   8877    {
   8878        // 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
   8879        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
   8880
   8881        // Select window to focus
   8882        const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
   8883        if (focus_change_dir != 0)
   8884        {
   8885            NavUpdateWindowingHighlightWindow(focus_change_dir);
   8886            g.NavWindowingHighlightAlpha = 1.0f;
   8887        }
   8888
   8889        // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)
   8890        if (!IsNavInputDown(ImGuiNavInput_Menu))
   8891        {
   8892            g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
   8893            if (g.NavWindowingToggleLayer && g.NavWindow)
   8894                apply_toggle_layer = true;
   8895            else if (!g.NavWindowingToggleLayer)
   8896                apply_focus_window = g.NavWindowingTarget;
   8897            g.NavWindowingTarget = NULL;
   8898        }
   8899    }
   8900
   8901    // Keyboard: Focus
   8902    if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard)
   8903    {
   8904        // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
   8905        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
   8906        if (IsKeyPressedMap(ImGuiKey_Tab, true))
   8907            NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
   8908        if (!g.IO.KeyCtrl)
   8909            apply_focus_window = g.NavWindowingTarget;
   8910    }
   8911
   8912    // Keyboard: Press and Release ALT to toggle menu layer
   8913    // 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
   8914    if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed))
   8915        g.NavWindowingToggleLayer = true;
   8916    if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
   8917        if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
   8918            apply_toggle_layer = true;
   8919
   8920    // Move window
   8921    if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
   8922    {
   8923        ImVec2 move_delta;
   8924        if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift)
   8925            move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
   8926        if (g.NavInputSource == ImGuiInputSource_NavGamepad)
   8927            move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
   8928        if (move_delta.x != 0.0f || move_delta.y != 0.0f)
   8929        {
   8930            const float NAV_MOVE_SPEED = 800.0f;
   8931            const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well
   8932            SetWindowPos(g.NavWindowingTarget->RootWindow, g.NavWindowingTarget->RootWindow->Pos + move_delta * move_speed, ImGuiCond_Always);
   8933            g.NavDisableMouseHover = true;
   8934            MarkIniSettingsDirty(g.NavWindowingTarget);
   8935        }
   8936    }
   8937
   8938    // Apply final focus
   8939    if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
   8940    {
   8941        ClearActiveID();
   8942        g.NavDisableHighlight = false;
   8943        g.NavDisableMouseHover = true;
   8944        apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
   8945        ClosePopupsOverWindow(apply_focus_window, false);
   8946        FocusWindow(apply_focus_window);
   8947        if (apply_focus_window->NavLastIds[0] == 0)
   8948            NavInitWindow(apply_focus_window, false);
   8949
   8950        // If the window only has a menu layer, select it directly
   8951        if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
   8952            g.NavLayer = ImGuiNavLayer_Menu;
   8953    }
   8954    if (apply_focus_window)
   8955        g.NavWindowingTarget = NULL;
   8956
   8957    // Apply menu/layer toggle
   8958    if (apply_toggle_layer && g.NavWindow)
   8959    {
   8960        // Move to parent menu if necessary
   8961        ImGuiWindow* new_nav_window = g.NavWindow;
   8962        while (new_nav_window->ParentWindow
   8963            && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
   8964            && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
   8965            && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
   8966            new_nav_window = new_nav_window->ParentWindow;
   8967        if (new_nav_window != g.NavWindow)
   8968        {
   8969            ImGuiWindow* old_nav_window = g.NavWindow;
   8970            FocusWindow(new_nav_window);
   8971            new_nav_window->NavLastChildNavWindow = old_nav_window;
   8972        }
   8973        g.NavDisableHighlight = false;
   8974        g.NavDisableMouseHover = true;
   8975
   8976        // When entering a regular menu bar with the Alt key, we always reinitialize the navigation ID.
   8977        const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
   8978        NavRestoreLayer(new_nav_layer);
   8979    }
   8980}
   8981
   8982// Window has already passed the IsWindowNavFocusable()
   8983static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
   8984{
   8985    if (window->Flags & ImGuiWindowFlags_Popup)
   8986        return "(Popup)";
   8987    if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
   8988        return "(Main menu bar)";
   8989    return "(Untitled)";
   8990}
   8991
   8992// Overlay displayed when using CTRL+TAB. Called by EndFrame().
   8993void ImGui::NavUpdateWindowingOverlay()
   8994{
   8995    ImGuiContext& g = *GImGui;
   8996    IM_ASSERT(g.NavWindowingTarget != NULL);
   8997
   8998    if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)
   8999        return;
   9000
   9001    if (g.NavWindowingList == NULL)
   9002        g.NavWindowingList = FindWindowByName("###NavWindowingList");
   9003    SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
   9004    SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
   9005    PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
   9006    Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
   9007    for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
   9008    {
   9009        ImGuiWindow* window = g.WindowsFocusOrder[n];
   9010        if (!IsWindowNavFocusable(window))
   9011            continue;
   9012        const char* label = window->Name;
   9013        if (label == FindRenderedTextEnd(label))
   9014            label = GetFallbackWindowNameForWindowingList(window);
   9015        Selectable(label, g.NavWindowingTarget == window);
   9016    }
   9017    End();
   9018    PopStyleVar();
   9019}
   9020
   9021//-----------------------------------------------------------------------------
   9022// [SECTION] DRAG AND DROP
   9023//-----------------------------------------------------------------------------
   9024
   9025void ImGui::ClearDragDrop()
   9026{
   9027    ImGuiContext& g = *GImGui;
   9028    g.DragDropActive = false;
   9029    g.DragDropPayload.Clear();
   9030    g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
   9031    g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
   9032    g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
   9033    g.DragDropAcceptFrameCount = -1;
   9034
   9035    g.DragDropPayloadBufHeap.clear();
   9036    memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
   9037}
   9038
   9039// Call when current ID is active.
   9040// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
   9041bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
   9042{
   9043    ImGuiContext& g = *GImGui;
   9044    ImGuiWindow* window = g.CurrentWindow;
   9045
   9046    bool source_drag_active = false;
   9047    ImGuiID source_id = 0;
   9048    ImGuiID source_parent_id = 0;
   9049    ImGuiMouseButton mouse_button = ImGuiMouseButton_Left;
   9050    if (!(flags & ImGuiDragDropFlags_SourceExtern))
   9051    {
   9052        source_id = window->DC.LastItemId;
   9053        if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case
   9054            return false;
   9055        if (g.IO.MouseDown[mouse_button] == false)
   9056            return false;
   9057
   9058        if (source_id == 0)
   9059        {
   9060            // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
   9061            // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
   9062            if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
   9063            {
   9064                IM_ASSERT(0);
   9065                return false;
   9066            }
   9067
   9068            // Early out
   9069            if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
   9070                return false;
   9071
   9072            // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
   9073            // We build a throwaway ID based on current ID stack + relative AABB of items in window.
   9074            // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
   9075            // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
   9076            source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
   9077            bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id);
   9078            if (is_hovered && g.IO.MouseClicked[mouse_button])
   9079            {
   9080                SetActiveID(source_id, window);
   9081                FocusWindow(window);
   9082            }
   9083            if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
   9084                g.ActiveIdAllowOverlap = is_hovered;
   9085        }
   9086        else
   9087        {
   9088            g.ActiveIdAllowOverlap = false;
   9089        }
   9090        if (g.ActiveId != source_id)
   9091            return false;
   9092        source_parent_id = window->IDStack.back();
   9093        source_drag_active = IsMouseDragging(mouse_button);
   9094
   9095        // Disable navigation and key inputs while dragging
   9096        g.ActiveIdUsingNavDirMask = ~(ImU32)0;
   9097        g.ActiveIdUsingNavInputMask = ~(ImU32)0;
   9098        g.ActiveIdUsingKeyInputMask = ~(ImU64)0;
   9099    }
   9100    else
   9101    {
   9102        window = NULL;
   9103        source_id = ImHashStr("#SourceExtern");
   9104        source_drag_active = true;
   9105    }
   9106
   9107    if (source_drag_active)
   9108    {
   9109        if (!g.DragDropActive)
   9110        {
   9111            IM_ASSERT(source_id != 0);
   9112            ClearDragDrop();
   9113            ImGuiPayload& payload = g.DragDropPayload;
   9114            payload.SourceId = source_id;
   9115            payload.SourceParentId = source_parent_id;
   9116            g.DragDropActive = true;
   9117            g.DragDropSourceFlags = flags;
   9118            g.DragDropMouseButton = mouse_button;
   9119        }
   9120        g.DragDropSourceFrameCount = g.FrameCount;
   9121        g.DragDropWithinSource = true;
   9122
   9123        if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
   9124        {
   9125            // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
   9126            // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
   9127            BeginTooltip();
   9128            if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
   9129            {
   9130                ImGuiWindow* tooltip_window = g.CurrentWindow;
   9131                tooltip_window->SkipItems = true;
   9132                tooltip_window->HiddenFramesCanSkipItems = 1;
   9133            }
   9134        }
   9135
   9136        if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
   9137            window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
   9138
   9139        return true;
   9140    }
   9141    return false;
   9142}
   9143
   9144void ImGui::EndDragDropSource()
   9145{
   9146    ImGuiContext& g = *GImGui;
   9147    IM_ASSERT(g.DragDropActive);
   9148    IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?");
   9149
   9150    if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
   9151        EndTooltip();
   9152
   9153    // Discard the drag if have not called SetDragDropPayload()
   9154    if (g.DragDropPayload.DataFrameCount == -1)
   9155        ClearDragDrop();
   9156    g.DragDropWithinSource = false;
   9157}
   9158
   9159// Use 'cond' to choose to submit payload on drag start or every frame
   9160bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
   9161{
   9162    ImGuiContext& g = *GImGui;
   9163    ImGuiPayload& payload = g.DragDropPayload;
   9164    if (cond == 0)
   9165        cond = ImGuiCond_Always;
   9166
   9167    IM_ASSERT(type != NULL);
   9168    IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
   9169    IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
   9170    IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
   9171    IM_ASSERT(payload.SourceId != 0);                               // Not called between BeginDragDropSource() and EndDragDropSource()
   9172
   9173    if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
   9174    {
   9175        // Copy payload
   9176        ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
   9177        g.DragDropPayloadBufHeap.resize(0);
   9178        if (data_size > sizeof(g.DragDropPayloadBufLocal))
   9179        {
   9180            // Store in heap
   9181            g.DragDropPayloadBufHeap.resize((int)data_size);
   9182            payload.Data = g.DragDropPayloadBufHeap.Data;
   9183            memcpy(payload.Data, data, data_size);
   9184        }
   9185        else if (data_size > 0)
   9186        {
   9187            // Store locally
   9188            memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
   9189            payload.Data = g.DragDropPayloadBufLocal;
   9190            memcpy(payload.Data, data, data_size);
   9191        }
   9192        else
   9193        {
   9194            payload.Data = NULL;
   9195        }
   9196        payload.DataSize = (int)data_size;
   9197    }
   9198    payload.DataFrameCount = g.FrameCount;
   9199
   9200    return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
   9201}
   9202
   9203bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
   9204{
   9205    ImGuiContext& g = *GImGui;
   9206    if (!g.DragDropActive)
   9207        return false;
   9208
   9209    ImGuiWindow* window = g.CurrentWindow;
   9210    if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
   9211        return false;
   9212    IM_ASSERT(id != 0);
   9213    if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
   9214        return false;
   9215    if (window->SkipItems)
   9216        return false;
   9217
   9218    IM_ASSERT(g.DragDropWithinTarget == false);
   9219    g.DragDropTargetRect = bb;
   9220    g.DragDropTargetId = id;
   9221    g.DragDropWithinTarget = true;
   9222    return true;
   9223}
   9224
   9225// We don't use BeginDragDropTargetCustom() and duplicate its code because:
   9226// 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.
   9227// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
   9228// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
   9229bool ImGui::BeginDragDropTarget()
   9230{
   9231    ImGuiContext& g = *GImGui;
   9232    if (!g.DragDropActive)
   9233        return false;
   9234
   9235    ImGuiWindow* window = g.CurrentWindow;
   9236    if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
   9237        return false;
   9238    if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
   9239        return false;
   9240
   9241    const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
   9242    ImGuiID id = window->DC.LastItemId;
   9243    if (id == 0)
   9244        id = window->GetIDFromRectangle(display_rect);
   9245    if (g.DragDropPayload.SourceId == id)
   9246        return false;
   9247
   9248    IM_ASSERT(g.DragDropWithinTarget == false);
   9249    g.DragDropTargetRect = display_rect;
   9250    g.DragDropTargetId = id;
   9251    g.DragDropWithinTarget = true;
   9252    return true;
   9253}
   9254
   9255bool ImGui::IsDragDropPayloadBeingAccepted()
   9256{
   9257    ImGuiContext& g = *GImGui;
   9258    return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
   9259}
   9260
   9261const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags)
   9262{
   9263    ImGuiContext& g = *GImGui;
   9264    ImGuiWindow* window = g.CurrentWindow;
   9265    ImGuiPayload& payload = g.DragDropPayload;
   9266    IM_ASSERT(g.DragDropActive);                        // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
   9267    IM_ASSERT(payload.DataFrameCount != -1);            // Forgot to call EndDragDropTarget() ?
   9268    if (type != NULL && !payload.IsDataType(type))
   9269        return NULL;
   9270
   9271    // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
   9272    // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
   9273    const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
   9274    ImRect r = g.DragDropTargetRect;
   9275    float r_surface = r.GetWidth() * r.GetHeight();
   9276    if (r_surface < g.DragDropAcceptIdCurrRectSurface)
   9277    {
   9278        g.DragDropAcceptFlags = flags;
   9279        g.DragDropAcceptIdCurr = g.DragDropTargetId;
   9280        g.DragDropAcceptIdCurrRectSurface = r_surface;
   9281    }
   9282
   9283    // Render default drop visuals
   9284    payload.Preview = was_accepted_previously;
   9285    flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
   9286    if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
   9287    {
   9288        // FIXME-DRAG: Settle on a proper default visuals for drop target.
   9289        r.Expand(3.5f);
   9290        bool push_clip_rect = !window->ClipRect.Contains(r);
   9291        if (push_clip_rect) window->DrawList->PushClipRect(r.Min-ImVec2(1,1), r.Max+ImVec2(1,1));
   9292        window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f);
   9293        if (push_clip_rect) window->DrawList->PopClipRect();
   9294    }
   9295
   9296    g.DragDropAcceptFrameCount = g.FrameCount;
   9297    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()
   9298    if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
   9299        return NULL;
   9300
   9301    return &payload;
   9302}
   9303
   9304const ImGuiPayload* ImGui::GetDragDropPayload()
   9305{
   9306    ImGuiContext& g = *GImGui;
   9307    return g.DragDropActive ? &g.DragDropPayload : NULL;
   9308}
   9309
   9310// We don't really use/need this now, but added it for the sake of consistency and because we might need it later.
   9311void ImGui::EndDragDropTarget()
   9312{
   9313    ImGuiContext& g = *GImGui;
   9314    IM_ASSERT(g.DragDropActive);
   9315    IM_ASSERT(g.DragDropWithinTarget);
   9316    g.DragDropWithinTarget = false;
   9317}
   9318
   9319//-----------------------------------------------------------------------------
   9320// [SECTION] LOGGING/CAPTURING
   9321//-----------------------------------------------------------------------------
   9322// All text output from the interface can be captured into tty/file/clipboard.
   9323// By default, tree nodes are automatically opened during logging.
   9324//-----------------------------------------------------------------------------
   9325
   9326// Pass text data straight to log (without being displayed)
   9327void ImGui::LogText(const char* fmt, ...)
   9328{
   9329    ImGuiContext& g = *GImGui;
   9330    if (!g.LogEnabled)
   9331        return;
   9332
   9333    va_list args;
   9334    va_start(args, fmt);
   9335    if (g.LogFile)
   9336    {
   9337        g.LogBuffer.Buf.resize(0);
   9338        g.LogBuffer.appendfv(fmt, args);
   9339        ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);
   9340    }
   9341    else
   9342    {
   9343        g.LogBuffer.appendfv(fmt, args);
   9344    }
   9345    va_end(args);
   9346}
   9347
   9348// Internal version that takes a position to decide on newline placement and pad items according to their depth.
   9349// We split text into individual lines to add current tree level padding
   9350void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)
   9351{
   9352    ImGuiContext& g = *GImGui;
   9353    ImGuiWindow* window = g.CurrentWindow;
   9354
   9355    if (!text_end)
   9356        text_end = FindRenderedTextEnd(text, text_end);
   9357
   9358    const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1);
   9359    if (ref_pos)
   9360        g.LogLinePosY = ref_pos->y;
   9361    if (log_new_line)
   9362        g.LogLineFirstItem = true;
   9363
   9364    const char* text_remaining = text;
   9365    if (g.LogDepthRef > window->DC.TreeDepth)  // Re-adjust padding if we have popped out of our starting depth
   9366        g.LogDepthRef = window->DC.TreeDepth;
   9367    const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef);
   9368    for (;;)
   9369    {
   9370        // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
   9371        // We don't add a trailing \n to allow a subsequent item on the same line to be captured.
   9372        const char* line_start = text_remaining;
   9373        const char* line_end = ImStreolRange(line_start, text_end);
   9374        const bool is_first_line = (line_start == text);
   9375        const bool is_last_line = (line_end == text_end);
   9376        if (!is_last_line || (line_start != line_end))
   9377        {
   9378            const int char_count = (int)(line_end - line_start);
   9379            if (log_new_line || !is_first_line)
   9380                LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start);
   9381            else if (g.LogLineFirstItem)
   9382                LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start);
   9383            else
   9384                LogText(" %.*s", char_count, line_start);
   9385            g.LogLineFirstItem = false;
   9386        }
   9387        else if (log_new_line)
   9388        {
   9389            // An empty "" string at a different Y position should output a carriage return.
   9390            LogText(IM_NEWLINE);
   9391            break;
   9392        }
   9393
   9394        if (is_last_line)
   9395            break;
   9396        text_remaining = line_end + 1;
   9397    }
   9398}
   9399
   9400// Start logging/capturing text output
   9401void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)
   9402{
   9403    ImGuiContext& g = *GImGui;
   9404    ImGuiWindow* window = g.CurrentWindow;
   9405    IM_ASSERT(g.LogEnabled == false);
   9406    IM_ASSERT(g.LogFile == NULL);
   9407    IM_ASSERT(g.LogBuffer.empty());
   9408    g.LogEnabled = true;
   9409    g.LogType = type;
   9410    g.LogDepthRef = window->DC.TreeDepth;
   9411    g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault);
   9412    g.LogLinePosY = FLT_MAX;
   9413    g.LogLineFirstItem = true;
   9414}
   9415
   9416void ImGui::LogToTTY(int auto_open_depth)
   9417{
   9418    ImGuiContext& g = *GImGui;
   9419    if (g.LogEnabled)
   9420        return;
   9421    IM_UNUSED(auto_open_depth);
   9422#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
   9423    LogBegin(ImGuiLogType_TTY, auto_open_depth);
   9424    g.LogFile = stdout;
   9425#endif
   9426}
   9427
   9428// Start logging/capturing text output to given file
   9429void ImGui::LogToFile(int auto_open_depth, const char* filename)
   9430{
   9431    ImGuiContext& g = *GImGui;
   9432    if (g.LogEnabled)
   9433        return;
   9434
   9435    // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still
   9436    // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE.
   9437    // By opening the file in binary mode "ab" we have consistent output everywhere.
   9438    if (!filename)
   9439        filename = g.IO.LogFilename;
   9440    if (!filename || !filename[0])
   9441        return;
   9442    ImFileHandle f = ImFileOpen(filename, "ab");
   9443    if (!f)
   9444    {
   9445        IM_ASSERT(0);
   9446        return;
   9447    }
   9448
   9449    LogBegin(ImGuiLogType_File, auto_open_depth);
   9450    g.LogFile = f;
   9451}
   9452
   9453// Start logging/capturing text output to clipboard
   9454void ImGui::LogToClipboard(int auto_open_depth)
   9455{
   9456    ImGuiContext& g = *GImGui;
   9457    if (g.LogEnabled)
   9458        return;
   9459    LogBegin(ImGuiLogType_Clipboard, auto_open_depth);
   9460}
   9461
   9462void ImGui::LogToBuffer(int auto_open_depth)
   9463{
   9464    ImGuiContext& g = *GImGui;
   9465    if (g.LogEnabled)
   9466        return;
   9467    LogBegin(ImGuiLogType_Buffer, auto_open_depth);
   9468}
   9469
   9470void ImGui::LogFinish()
   9471{
   9472    ImGuiContext& g = *GImGui;
   9473    if (!g.LogEnabled)
   9474        return;
   9475
   9476    LogText(IM_NEWLINE);
   9477    switch (g.LogType)
   9478    {
   9479    case ImGuiLogType_TTY:
   9480#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
   9481        fflush(g.LogFile);
   9482#endif
   9483        break;
   9484    case ImGuiLogType_File:
   9485        ImFileClose(g.LogFile);
   9486        break;
   9487    case ImGuiLogType_Buffer:
   9488        break;
   9489    case ImGuiLogType_Clipboard:
   9490        if (!g.LogBuffer.empty())
   9491            SetClipboardText(g.LogBuffer.begin());
   9492        break;
   9493    case ImGuiLogType_None:
   9494        IM_ASSERT(0);
   9495        break;
   9496    }
   9497
   9498    g.LogEnabled = false;
   9499    g.LogType = ImGuiLogType_None;
   9500    g.LogFile = NULL;
   9501    g.LogBuffer.clear();
   9502}
   9503
   9504// Helper to display logging buttons
   9505// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!)
   9506void ImGui::LogButtons()
   9507{
   9508    ImGuiContext& g = *GImGui;
   9509
   9510    PushID("LogButtons");
   9511#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
   9512    const bool log_to_tty = Button("Log To TTY"); SameLine();
   9513#else
   9514    const bool log_to_tty = false;
   9515#endif
   9516    const bool log_to_file = Button("Log To File"); SameLine();
   9517    const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
   9518    PushAllowKeyboardFocus(false);
   9519    SetNextItemWidth(80.0f);
   9520    SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL);
   9521    PopAllowKeyboardFocus();
   9522    PopID();
   9523
   9524    // Start logging at the end of the function so that the buttons don't appear in the log
   9525    if (log_to_tty)
   9526        LogToTTY();
   9527    if (log_to_file)
   9528        LogToFile();
   9529    if (log_to_clipboard)
   9530        LogToClipboard();
   9531}
   9532
   9533//-----------------------------------------------------------------------------
   9534// [SECTION] SETTINGS
   9535//-----------------------------------------------------------------------------
   9536
   9537// Called by NewFrame()
   9538void ImGui::UpdateSettings()
   9539{
   9540    // Load settings on first frame (if not explicitly loaded manually before)
   9541    ImGuiContext& g = *GImGui;
   9542    if (!g.SettingsLoaded)
   9543    {
   9544        IM_ASSERT(g.SettingsWindows.empty());
   9545        if (g.IO.IniFilename)
   9546            LoadIniSettingsFromDisk(g.IO.IniFilename);
   9547        g.SettingsLoaded = true;
   9548    }
   9549
   9550    // Save settings (with a delay after the last modification, so we don't spam disk too much)
   9551    if (g.SettingsDirtyTimer > 0.0f)
   9552    {
   9553        g.SettingsDirtyTimer -= g.IO.DeltaTime;
   9554        if (g.SettingsDirtyTimer <= 0.0f)
   9555        {
   9556            if (g.IO.IniFilename != NULL)
   9557                SaveIniSettingsToDisk(g.IO.IniFilename);
   9558            else
   9559                g.IO.WantSaveIniSettings = true;  // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
   9560            g.SettingsDirtyTimer = 0.0f;
   9561        }
   9562    }
   9563}
   9564
   9565void ImGui::MarkIniSettingsDirty()
   9566{
   9567    ImGuiContext& g = *GImGui;
   9568    if (g.SettingsDirtyTimer <= 0.0f)
   9569        g.SettingsDirtyTimer = g.IO.IniSavingRate;
   9570}
   9571
   9572void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
   9573{
   9574    ImGuiContext& g = *GImGui;
   9575    if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
   9576        if (g.SettingsDirtyTimer <= 0.0f)
   9577            g.SettingsDirtyTimer = g.IO.IniSavingRate;
   9578}
   9579
   9580ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
   9581{
   9582    ImGuiContext& g = *GImGui;
   9583
   9584#if !IMGUI_DEBUG_INI_SETTINGS
   9585    // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
   9586    // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
   9587    if (const char* p = strstr(name, "###"))
   9588        name = p;
   9589#endif
   9590    const size_t name_len = strlen(name);
   9591
   9592    // Allocate chunk
   9593    const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
   9594    ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
   9595    IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
   9596    settings->ID = ImHashStr(name, name_len);
   9597    memcpy(settings->GetName(), name, name_len + 1);   // Store with zero terminator
   9598
   9599    return settings;
   9600}
   9601
   9602ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
   9603{
   9604    ImGuiContext& g = *GImGui;
   9605    for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
   9606        if (settings->ID == id)
   9607            return settings;
   9608    return NULL;
   9609}
   9610
   9611ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
   9612{
   9613    if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name)))
   9614        return settings;
   9615    return CreateNewWindowSettings(name);
   9616}
   9617
   9618void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
   9619{
   9620    size_t file_data_size = 0;
   9621    char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
   9622    if (!file_data)
   9623        return;
   9624    LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
   9625    IM_FREE(file_data);
   9626}
   9627
   9628ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
   9629{
   9630    ImGuiContext& g = *GImGui;
   9631    const ImGuiID type_hash = ImHashStr(type_name);
   9632    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
   9633        if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
   9634            return &g.SettingsHandlers[handler_n];
   9635    return NULL;
   9636}
   9637
   9638// Zero-tolerance, no error reporting, cheap .ini parsing
   9639void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
   9640{
   9641    ImGuiContext& g = *GImGui;
   9642    IM_ASSERT(g.Initialized);
   9643    IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
   9644
   9645    // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
   9646    // 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..
   9647    if (ini_size == 0)
   9648        ini_size = strlen(ini_data);
   9649    char* buf = (char*)IM_ALLOC(ini_size + 1);
   9650    char* buf_end = buf + ini_size;
   9651    memcpy(buf, ini_data, ini_size);
   9652    buf[ini_size] = 0;
   9653
   9654    void* entry_data = NULL;
   9655    ImGuiSettingsHandler* entry_handler = NULL;
   9656
   9657    char* line_end = NULL;
   9658    for (char* line = buf; line < buf_end; line = line_end + 1)
   9659    {
   9660        // Skip new lines markers, then find end of the line
   9661        while (*line == '\n' || *line == '\r')
   9662            line++;
   9663        line_end = line;
   9664        while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
   9665            line_end++;
   9666        line_end[0] = 0;
   9667        if (line[0] == ';')
   9668            continue;
   9669        if (line[0] == '[' && line_end > line && line_end[-1] == ']')
   9670        {
   9671            // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
   9672            line_end[-1] = 0;
   9673            const char* name_end = line_end - 1;
   9674            const char* type_start = line + 1;
   9675            char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');
   9676            const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
   9677            if (!type_end || !name_start)
   9678                continue;
   9679            *type_end = 0; // Overwrite first ']'
   9680            name_start++;  // Skip second '['
   9681            entry_handler = FindSettingsHandler(type_start);
   9682            entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
   9683        }
   9684        else if (entry_handler != NULL && entry_data != NULL)
   9685        {
   9686            // Let type handler parse the line
   9687            entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
   9688        }
   9689    }
   9690    IM_FREE(buf);
   9691    g.SettingsLoaded = true;
   9692}
   9693
   9694void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
   9695{
   9696    ImGuiContext& g = *GImGui;
   9697    g.SettingsDirtyTimer = 0.0f;
   9698    if (!ini_filename)
   9699        return;
   9700
   9701    size_t ini_data_size = 0;
   9702    const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
   9703    ImFileHandle f = ImFileOpen(ini_filename, "wt");
   9704    if (!f)
   9705        return;
   9706    ImFileWrite(ini_data, sizeof(char), ini_data_size, f);
   9707    ImFileClose(f);
   9708}
   9709
   9710// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
   9711const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
   9712{
   9713    ImGuiContext& g = *GImGui;
   9714    g.SettingsDirtyTimer = 0.0f;
   9715    g.SettingsIniData.Buf.resize(0);
   9716    g.SettingsIniData.Buf.push_back(0);
   9717    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
   9718    {
   9719        ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
   9720        handler->WriteAllFn(&g, handler, &g.SettingsIniData);
   9721    }
   9722    if (out_size)
   9723        *out_size = (size_t)g.SettingsIniData.size();
   9724    return g.SettingsIniData.c_str();
   9725}
   9726
   9727static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
   9728{
   9729    ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name));
   9730    if (!settings)
   9731        settings = ImGui::CreateNewWindowSettings(name);
   9732    return (void*)settings;
   9733}
   9734
   9735static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
   9736{
   9737    ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
   9738    int x, y;
   9739    int i;
   9740    if (sscanf(line, "Pos=%i,%i", &x, &y) == 2)         settings->Pos = ImVec2ih((short)x, (short)y);
   9741    else if (sscanf(line, "Size=%i,%i", &x, &y) == 2)   settings->Size = ImVec2ih((short)x, (short)y);
   9742    else if (sscanf(line, "Collapsed=%d", &i) == 1)     settings->Collapsed = (i != 0);
   9743}
   9744
   9745static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
   9746{
   9747    // Gather data from windows that were active during this session
   9748    // (if a window wasn't opened in this session we preserve its settings)
   9749    ImGuiContext& g = *ctx;
   9750    for (int i = 0; i != g.Windows.Size; i++)
   9751    {
   9752        ImGuiWindow* window = g.Windows[i];
   9753        if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
   9754            continue;
   9755
   9756        ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID);
   9757        if (!settings)
   9758        {
   9759            settings = ImGui::CreateNewWindowSettings(window->Name);
   9760            window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
   9761        }
   9762        IM_ASSERT(settings->ID == window->ID);
   9763        settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y);
   9764        settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y);
   9765        settings->Collapsed = window->Collapsed;
   9766    }
   9767
   9768    // Write to text buffer
   9769    buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
   9770    for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
   9771    {
   9772        const char* settings_name = settings->GetName();
   9773        buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
   9774        buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
   9775        buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
   9776        buf->appendf("Collapsed=%d\n", settings->Collapsed);
   9777        buf->append("\n");
   9778    }
   9779}
   9780
   9781
   9782//-----------------------------------------------------------------------------
   9783// [SECTION] VIEWPORTS, PLATFORM WINDOWS
   9784//-----------------------------------------------------------------------------
   9785
   9786// (this section is filled in the 'docking' branch)
   9787
   9788
   9789//-----------------------------------------------------------------------------
   9790// [SECTION] DOCKING
   9791//-----------------------------------------------------------------------------
   9792
   9793// (this section is filled in the 'docking' branch)
   9794
   9795
   9796//-----------------------------------------------------------------------------
   9797// [SECTION] PLATFORM DEPENDENT HELPERS
   9798//-----------------------------------------------------------------------------
   9799
   9800#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
   9801
   9802#ifdef _MSC_VER
   9803#pragma comment(lib, "user32")
   9804#pragma comment(lib, "kernel32")
   9805#endif
   9806
   9807// Win32 clipboard implementation
   9808// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown()
   9809static const char* GetClipboardTextFn_DefaultImpl(void*)
   9810{
   9811    ImGuiContext& g = *GImGui;
   9812    g.ClipboardHandlerData.clear();
   9813    if (!::OpenClipboard(NULL))
   9814        return NULL;
   9815    HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
   9816    if (wbuf_handle == NULL)
   9817    {
   9818        ::CloseClipboard();
   9819        return NULL;
   9820    }
   9821    if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
   9822    {
   9823        int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
   9824        g.ClipboardHandlerData.resize(buf_len);
   9825        ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
   9826    }
   9827    ::GlobalUnlock(wbuf_handle);
   9828    ::CloseClipboard();
   9829    return g.ClipboardHandlerData.Data;
   9830}
   9831
   9832static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
   9833{
   9834    if (!::OpenClipboard(NULL))
   9835        return;
   9836    const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
   9837    HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
   9838    if (wbuf_handle == NULL)
   9839    {
   9840        ::CloseClipboard();
   9841        return;
   9842    }
   9843    WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
   9844    ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
   9845    ::GlobalUnlock(wbuf_handle);
   9846    ::EmptyClipboard();
   9847    if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
   9848        ::GlobalFree(wbuf_handle);
   9849    ::CloseClipboard();
   9850}
   9851
   9852#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
   9853
   9854#include <Carbon/Carbon.h>  // Use old API to avoid need for separate .mm file
   9855static PasteboardRef main_clipboard = 0;
   9856
   9857// OSX clipboard implementation
   9858// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!
   9859static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
   9860{
   9861    if (!main_clipboard)
   9862        PasteboardCreate(kPasteboardClipboard, &main_clipboard);
   9863    PasteboardClear(main_clipboard);
   9864    CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));
   9865    if (cf_data)
   9866    {
   9867        PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
   9868        CFRelease(cf_data);
   9869    }
   9870}
   9871
   9872static const char* GetClipboardTextFn_DefaultImpl(void*)
   9873{
   9874    if (!main_clipboard)
   9875        PasteboardCreate(kPasteboardClipboard, &main_clipboard);
   9876    PasteboardSynchronize(main_clipboard);
   9877
   9878    ItemCount item_count = 0;
   9879    PasteboardGetItemCount(main_clipboard, &item_count);
   9880    for (ItemCount i = 0; i < item_count; i++)
   9881    {
   9882        PasteboardItemID item_id = 0;
   9883        PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
   9884        CFArrayRef flavor_type_array = 0;
   9885        PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
   9886        for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
   9887        {
   9888            CFDataRef cf_data;
   9889            if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
   9890            {
   9891                ImGuiContext& g = *GImGui;
   9892                g.ClipboardHandlerData.clear();
   9893                int length = (int)CFDataGetLength(cf_data);
   9894                g.ClipboardHandlerData.resize(length + 1);
   9895                CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data);
   9896                g.ClipboardHandlerData[length] = 0;
   9897                CFRelease(cf_data);
   9898                return g.ClipboardHandlerData.Data;
   9899            }
   9900        }
   9901    }
   9902    return NULL;
   9903}
   9904
   9905#else
   9906
   9907// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
   9908static const char* GetClipboardTextFn_DefaultImpl(void*)
   9909{
   9910    ImGuiContext& g = *GImGui;
   9911    return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();
   9912}
   9913
   9914static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
   9915{
   9916    ImGuiContext& g = *GImGui;
   9917    g.ClipboardHandlerData.clear();
   9918    const char* text_end = text + strlen(text);
   9919    g.ClipboardHandlerData.resize((int)(text_end - text) + 1);
   9920    memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text));
   9921    g.ClipboardHandlerData[(int)(text_end - text)] = 0;
   9922}
   9923
   9924#endif
   9925
   9926// Win32 API IME support (for Asian languages, etc.)
   9927#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
   9928
   9929#include <imm.h>
   9930#ifdef _MSC_VER
   9931#pragma comment(lib, "imm32")
   9932#endif
   9933
   9934static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
   9935{
   9936    // Notify OS Input Method Editor of text input position
   9937    ImGuiIO& io = ImGui::GetIO();
   9938    if (HWND hwnd = (HWND)io.ImeWindowHandle)
   9939        if (HIMC himc = ::ImmGetContext(hwnd))
   9940        {
   9941            COMPOSITIONFORM cf;
   9942            cf.ptCurrentPos.x = x;
   9943            cf.ptCurrentPos.y = y;
   9944            cf.dwStyle = CFS_FORCE_POSITION;
   9945            ::ImmSetCompositionWindow(himc, &cf);
   9946            ::ImmReleaseContext(hwnd, himc);
   9947        }
   9948}
   9949
   9950#else
   9951
   9952static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
   9953
   9954#endif
   9955
   9956//-----------------------------------------------------------------------------
   9957// [SECTION] METRICS/DEBUG WINDOW
   9958//-----------------------------------------------------------------------------
   9959
   9960#ifndef IMGUI_DISABLE_METRICS_WINDOW
   9961// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
   9962static void MetricsHelpMarker(const char* desc)
   9963{
   9964    ImGui::TextDisabled("(?)");
   9965    if (ImGui::IsItemHovered())
   9966    {
   9967        ImGui::BeginTooltip();
   9968        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
   9969        ImGui::TextUnformatted(desc);
   9970        ImGui::PopTextWrapPos();
   9971        ImGui::EndTooltip();
   9972    }
   9973}
   9974
   9975void ImGui::ShowMetricsWindow(bool* p_open)
   9976{
   9977    if (!ImGui::Begin("Dear ImGui Metrics", p_open))
   9978    {
   9979        ImGui::End();
   9980        return;
   9981    }
   9982
   9983    // Debugging enums
   9984    enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type
   9985    const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" };
   9986    enum { TRT_OuterRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersDesired, TRT_ColumnsContentRowsFrozen, TRT_ColumnsContentRowsUnfrozen, TRT_Count }; // Tables Rect Type
   9987    const char* trt_rects_names[TRT_Count] = { "OuterRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersDesired", "ColumnsContentRowsFrozen", "ColumnsContentRowsUnfrozen" };
   9988
   9989    // State
   9990    static bool show_windows_rects = false;
   9991    static int  show_windows_rect_type = WRT_WorkRect;
   9992    static bool show_windows_begin_order = false;
   9993    static bool show_tables_rects = false;
   9994    static int  show_tables_rect_type = TRT_WorkRect;
   9995    static bool show_drawcmd_mesh = true;
   9996    static bool show_drawcmd_aabb = true;
   9997
   9998    // Basic info
   9999    ImGuiContext& g = *GImGui;
  10000    ImGuiIO& io = ImGui::GetIO();
  10001    ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
  10002    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
  10003    ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
  10004    ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows);
  10005    ImGui::Text("%d active allocations", io.MetricsActiveAllocations);
  10006    ImGui::Separator();
  10007
  10008    // Helper functions to display common structures:
  10009    // - NodeDrawList()
  10010    // - NodeColumns()
  10011    // - NodeWindow()
  10012    // - NodeWindows()
  10013    // - NodeTabBar()
  10014    // - NodeStorage()
  10015    struct Funcs
  10016    {
  10017        static ImRect GetWindowRect(ImGuiWindow* window, int rect_type)
  10018        {
  10019            if (rect_type == WRT_OuterRect)                 { return window->Rect(); }
  10020            else if (rect_type == WRT_OuterRectClipped)     { return window->OuterRectClipped; }
  10021            else if (rect_type == WRT_InnerRect)            { return window->InnerRect; }
  10022            else if (rect_type == WRT_InnerClipRect)        { return window->InnerClipRect; }
  10023            else if (rect_type == WRT_WorkRect)             { return window->WorkRect; }
  10024            else if (rect_type == WRT_Content)              { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
  10025            else if (rect_type == WRT_ContentRegionRect)    { return window->ContentRegionRect; }
  10026            IM_ASSERT(0);
  10027            return ImRect();
  10028        }
  10029
  10030        static void NodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, int elem_offset, bool show_mesh, bool show_aabb)
  10031        {
  10032            IM_ASSERT(show_mesh || show_aabb);
  10033            ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
  10034            ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
  10035
  10036            // Draw wire-frame version of all triangles
  10037            ImRect clip_rect = draw_cmd->ClipRect;
  10038            ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
  10039            ImDrawListFlags backup_flags = fg_draw_list->Flags;
  10040            fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
  10041            for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + draw_cmd->ElemCount); base_idx += 3)
  10042            {
  10043                ImVec2 triangle[3];
  10044                for (int n = 0; n < 3; n++)
  10045                {
  10046                    ImVec2 p = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos;
  10047                    triangle[n] = p;
  10048                    vtxs_rect.Add(p);
  10049                }
  10050                if (show_mesh)
  10051                    fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); // In yellow: mesh triangles
  10052            }
  10053            // Draw bounding boxes
  10054            if (show_aabb)
  10055            {
  10056                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
  10057                fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles
  10058            }
  10059            fg_draw_list->Flags = backup_flags;
  10060        }
  10061
  10062        static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
  10063        {
  10064            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);
  10065            if (draw_list == ImGui::GetWindowDrawList())
  10066            {
  10067                ImGui::SameLine();
  10068                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)
  10069                if (node_open) ImGui::TreePop();
  10070                return;
  10071            }
  10072
  10073            ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
  10074            if (window && IsItemHovered())
  10075                fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
  10076            if (!node_open)
  10077                return;
  10078
  10079            if (window && !window->WasActive)
  10080                ImGui::TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!");
  10081
  10082            unsigned int elem_offset = 0;
  10083            for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
  10084            {
  10085                if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0)
  10086                    continue;
  10087                if (pcmd->UserCallback)
  10088                {
  10089                    ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
  10090                    continue;
  10091                }
  10092
  10093                ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
  10094                char buf[300];
  10095                ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd: %4d triangles, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
  10096                    pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId,
  10097                    pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
  10098                bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
  10099                if (ImGui::IsItemHovered() && (show_drawcmd_mesh || show_drawcmd_aabb) && fg_draw_list)
  10100                    NodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, elem_offset, show_drawcmd_mesh, show_drawcmd_aabb);
  10101                if (!pcmd_node_open)
  10102                    continue;
  10103
  10104                // Calculate approximate coverage area (touched pixel count)
  10105                // This will be in pixels squared as long there's no post-scaling happening to the renderer output.
  10106                float total_area = 0.0f;
  10107                for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3)
  10108                {
  10109                    ImVec2 triangle[3];
  10110                    for (int n = 0; n < 3; n++)
  10111                        triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos;
  10112                    total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);
  10113                }
  10114
  10115                // Display vertex information summary. Hover to get all triangles drawn in wire-frame
  10116                ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);
  10117                ImGui::Selectable(buf);
  10118                if (ImGui::IsItemHovered() && fg_draw_list)
  10119                    NodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, elem_offset, true, false);
  10120
  10121                // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
  10122                ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
  10123                while (clipper.Step())
  10124                    for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
  10125                    {
  10126                        char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
  10127                        ImVec2 triangle[3];
  10128                        for (int n = 0; n < 3; n++, idx_i++)
  10129                        {
  10130                            ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[idx_i] : idx_i];
  10131                            triangle[n] = v.pos;
  10132                            buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
  10133                                (n == 0) ? "Vert:" : "     ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
  10134                        }
  10135
  10136                        ImGui::Selectable(buf, false);
  10137                        if (fg_draw_list && ImGui::IsItemHovered())
  10138                        {
  10139                            ImDrawListFlags backup_flags = fg_draw_list->Flags;
  10140                            fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
  10141                            fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255,255,0,255), true, 1.0f);
  10142                            fg_draw_list->Flags = backup_flags;
  10143                        }
  10144                    }
  10145                ImGui::TreePop();
  10146            }
  10147            ImGui::TreePop();
  10148        }
  10149
  10150        static void NodeColumns(const ImGuiColumns* columns)
  10151        {
  10152            if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
  10153                return;
  10154            ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
  10155            for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
  10156                ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
  10157            ImGui::TreePop();
  10158        }
  10159
  10160        static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
  10161        {
  10162            if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size))
  10163                return;
  10164            for (int i = 0; i < windows.Size; i++)
  10165            {
  10166                ImGui::PushID(windows[i]);
  10167                Funcs::NodeWindow(windows[i], "Window");
  10168                ImGui::PopID();
  10169            }
  10170            ImGui::TreePop();
  10171        }
  10172
  10173        static void NodeWindow(ImGuiWindow* window, const char* label)
  10174        {
  10175            if (window == NULL)
  10176            {
  10177                ImGui::BulletText("%s: NULL", label);
  10178                return;
  10179            }
  10180            bool open = ImGui::TreeNode(label, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window);
  10181            if (ImGui::IsItemHovered() && window->WasActive)
  10182                ImGui::GetForegroundDrawList()->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
  10183            if (!open)
  10184                return;
  10185
  10186            if (!window->WasActive)
  10187                ImGui::TextDisabled("Note: window is not currently visible.");
  10188            if (window->MemoryCompacted)
  10189                ImGui::TextDisabled("Note: some memory buffers have been compacted/freed.");
  10190
  10191            ImGuiWindowFlags flags = window->Flags;
  10192            NodeDrawList(window, window->DrawList, "DrawList");
  10193            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);
  10194            ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
  10195                (flags & ImGuiWindowFlags_ChildWindow)  ? "Child " : "",      (flags & ImGuiWindowFlags_Tooltip)     ? "Tooltip "   : "",  (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
  10196                (flags & ImGuiWindowFlags_Modal)        ? "Modal " : "",      (flags & ImGuiWindowFlags_ChildMenu)   ? "ChildMenu " : "",  (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
  10197                (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
  10198            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" : "");
  10199            ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
  10200            ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
  10201            ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
  10202            ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
  10203            if (!window->NavRectRel[0].IsInverted())
  10204                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);
  10205            else
  10206                ImGui::BulletText("NavRectRel[0]: <None>");
  10207            if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
  10208            if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow");
  10209            if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
  10210            if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
  10211            {
  10212                for (int n = 0; n < window->ColumnsStorage.Size; n++)
  10213                    NodeColumns(&window->ColumnsStorage[n]);
  10214                ImGui::TreePop();
  10215            }
  10216            NodeStorage(&window->StateStorage, "Storage");
  10217            ImGui::TreePop();
  10218        }
  10219
  10220        static void NodeTabBar(ImGuiTabBar* tab_bar)
  10221        {
  10222            // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.
  10223            char buf[256];
  10224            char* p = buf;
  10225            const char* buf_end = buf + IM_ARRAYSIZE(buf);
  10226            p += ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : "");
  10227            if (ImGui::TreeNode(tab_bar, "%s", buf))
  10228            {
  10229                for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
  10230                {
  10231                    const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
  10232                    ImGui::PushID(tab);
  10233                    if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2);
  10234                    if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine();
  10235                    ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "");
  10236                    ImGui::PopID();
  10237                }
  10238                ImGui::TreePop();
  10239            }
  10240        }
  10241
  10242        static void NodeStorage(ImGuiStorage* storage, const char* label)
  10243        {
  10244            if (!ImGui::TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
  10245                return;
  10246            for (int n = 0; n < storage->Data.Size; n++)
  10247            {
  10248                const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
  10249                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.
  10250            }
  10251            ImGui::TreePop();
  10252        }
  10253    };
  10254
  10255
  10256    // Tools
  10257    if (ImGui::TreeNode("Tools"))
  10258    {
  10259        // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
  10260        if (ImGui::Button("Item Picker.."))
  10261            ImGui::DebugStartItemPicker();
  10262        ImGui::SameLine();
  10263        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.");
  10264
  10265        ImGui::Checkbox("Show windows begin order", &show_windows_begin_order);
  10266        ImGui::Checkbox("Show windows rectangles", &show_windows_rects);
  10267        ImGui::SameLine();
  10268        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
  10269        show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count, WRT_Count);
  10270        if (show_windows_rects && g.NavWindow)
  10271        {
  10272            ImGui::BulletText("'%s':", g.NavWindow->Name);
  10273            ImGui::Indent();
  10274            for (int rect_n = 0; rect_n < WRT_Count; rect_n++)
  10275            {
  10276                ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n);
  10277                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]);
  10278            }
  10279            ImGui::Unindent();
  10280        }
  10281        ImGui::Checkbox("Show mesh when hovering ImDrawCmd", &show_drawcmd_mesh);
  10282        ImGui::Checkbox("Show bounding boxes when hovering ImDrawCmd", &show_drawcmd_aabb);
  10283        ImGui::TreePop();
  10284    }
  10285
  10286    // Contents
  10287    Funcs::NodeWindows(g.Windows, "Windows");
  10288    //Funcs::NodeWindows(g.WindowsFocusOrder, "WindowsFocusOrder");
  10289    if (ImGui::TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
  10290    {
  10291        for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
  10292            Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList");
  10293        ImGui::TreePop();
  10294    }
  10295
  10296    // Details for Popups
  10297    if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
  10298    {
  10299        for (int i = 0; i < g.OpenPopupStack.Size; i++)
  10300        {
  10301            ImGuiWindow* window = g.OpenPopupStack[i].Window;
  10302            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" : "");
  10303        }
  10304        ImGui::TreePop();
  10305    }
  10306
  10307    // Details for TabBars
  10308    if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
  10309    {
  10310        for (int n = 0; n < g.TabBars.GetSize(); n++)
  10311            Funcs::NodeTabBar(g.TabBars.GetByIndex(n));
  10312        ImGui::TreePop();
  10313    }
  10314
  10315    // Details for Tables
  10316    IM_UNUSED(trt_rects_names);
  10317    IM_UNUSED(show_tables_rects);
  10318    IM_UNUSED(show_tables_rect_type);
  10319#ifdef IMGUI_HAS_TABLE
  10320    if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
  10321    {
  10322        for (int n = 0; n < g.Tables.GetSize(); n++)
  10323            Funcs::NodeTable(g.Tables.GetByIndex(n));
  10324        ImGui::TreePop();
  10325    }
  10326#endif // #define IMGUI_HAS_TABLE
  10327
  10328    // Details for Docking
  10329#ifdef IMGUI_HAS_DOCK
  10330    if (ImGui::TreeNode("Docking"))
  10331    {
  10332        ImGui::TreePop();
  10333    }
  10334#endif // #define IMGUI_HAS_DOCK
  10335
  10336    // Misc Details
  10337    if (ImGui::TreeNode("Internal state"))
  10338    {
  10339        const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
  10340        ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
  10341        ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
  10342        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
  10343        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]);
  10344        ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
  10345        ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
  10346        ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
  10347        ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
  10348        ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
  10349        ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
  10350        ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
  10351        ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
  10352        ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
  10353        ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
  10354        ImGui::TreePop();
  10355    }
  10356
  10357    // Overlay: Display windows Rectangles and Begin Order
  10358    if (show_windows_rects || show_windows_begin_order)
  10359    {
  10360        for (int n = 0; n < g.Windows.Size; n++)
  10361        {
  10362            ImGuiWindow* window = g.Windows[n];
  10363            if (!window->WasActive)
  10364                continue;
  10365            ImDrawList* draw_list = GetForegroundDrawList(window);
  10366            if (show_windows_rects)
  10367            {
  10368                ImRect r = Funcs::GetWindowRect(window, show_windows_rect_type);
  10369                draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
  10370            }
  10371            if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow))
  10372            {
  10373                char buf[32];
  10374                ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
  10375                float font_size = ImGui::GetFontSize();
  10376                draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
  10377                draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf);
  10378            }
  10379        }
  10380    }
  10381
  10382#ifdef IMGUI_HAS_TABLE
  10383    // Overlay: Display Tables Rectangles
  10384    if (show_tables_rects)
  10385    {
  10386        for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
  10387        {
  10388            ImGuiTable* table = g.Tables.GetByIndex(table_n);
  10389        }
  10390    }
  10391#endif // #define IMGUI_HAS_TABLE
  10392
  10393#ifdef IMGUI_HAS_DOCK
  10394    // Overlay: Display Docking info
  10395    if (show_docking_nodes && g.IO.KeyCtrl)
  10396    {
  10397    }
  10398#endif // #define IMGUI_HAS_DOCK
  10399
  10400    ImGui::End();
  10401}
  10402
  10403#else
  10404
  10405void ImGui::ShowMetricsWindow(bool*) { }
  10406
  10407#endif
  10408
  10409//-----------------------------------------------------------------------------
  10410
  10411// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
  10412// 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.
  10413#ifdef IMGUI_INCLUDE_IMGUI_USER_INL
  10414#include "imgui_user.inl"
  10415#endif
  10416
  10417//-----------------------------------------------------------------------------
  10418
  10419#endif // #ifndef IMGUI_DISABLE