imgui

FORK: Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
git clone https://git.neptards.moe/neptards/imgui.git
Log | Files | Refs

imgui.cpp (570555B)


      1 // dear imgui, v1.83
      2 // (main code and documentation)
      3 
      4 // Help:
      5 // - Read FAQ at http://dearimgui.org/faq
      6 // - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
      7 // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
      8 // Read imgui.cpp for details, links and comments.
      9 
     10 // Resources:
     11 // - FAQ                   http://dearimgui.org/faq
     12 // - Homepage & latest     https://github.com/ocornut/imgui
     13 // - Releases & changelog  https://github.com/ocornut/imgui/releases
     14 // - Gallery               https://github.com/ocornut/imgui/issues/3793 (please post your screenshots/video there!)
     15 // - Wiki                  https://github.com/ocornut/imgui/wiki (lots of good stuff there)
     16 // - Glossary              https://github.com/ocornut/imgui/wiki/Glossary
     17 // - Issues & support      https://github.com/ocornut/imgui/issues
     18 // - Discussions           https://github.com/ocornut/imgui/discussions
     19 
     20 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
     21 // See LICENSE.txt for copyright and licensing details (standard MIT License).
     22 // This library is free but needs your support to sustain development and maintenance.
     23 // Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.com".
     24 // Individuals: you can support continued development via donations. See docs/README or web page.
     25 
     26 // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
     27 // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
     28 // modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
     29 // come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
     30 // to a better solution or official support for them.
     31 
     32 /*
     33 
     34 Index of this file:
     35 
     36 DOCUMENTATION
     37 
     38 - MISSION STATEMENT
     39 - END-USER GUIDE
     40 - PROGRAMMER GUIDE
     41   - READ FIRST
     42   - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
     43   - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
     44   - HOW A SIMPLE APPLICATION MAY LOOK LIKE
     45   - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
     46   - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
     47 - API BREAKING CHANGES (read me when you update!)
     48 - FREQUENTLY ASKED QUESTIONS (FAQ)
     49   - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer)
     50 
     51 CODE
     52 (search for "[SECTION]" in the code to find them)
     53 
     54 // [SECTION] INCLUDES
     55 // [SECTION] FORWARD DECLARATIONS
     56 // [SECTION] CONTEXT AND MEMORY ALLOCATORS
     57 // [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
     58 // [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
     59 // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
     60 // [SECTION] MISC HELPERS/UTILITIES (File functions)
     61 // [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
     62 // [SECTION] MISC HELPERS/UTILITIES (Color functions)
     63 // [SECTION] ImGuiStorage
     64 // [SECTION] ImGuiTextFilter
     65 // [SECTION] ImGuiTextBuffer
     66 // [SECTION] ImGuiListClipper
     67 // [SECTION] STYLING
     68 // [SECTION] RENDER HELPERS
     69 // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
     70 // [SECTION] ERROR CHECKING
     71 // [SECTION] LAYOUT
     72 // [SECTION] SCROLLING
     73 // [SECTION] TOOLTIPS
     74 // [SECTION] POPUPS
     75 // [SECTION] KEYBOARD/GAMEPAD NAVIGATION
     76 // [SECTION] DRAG AND DROP
     77 // [SECTION] LOGGING/CAPTURING
     78 // [SECTION] SETTINGS
     79 // [SECTION] VIEWPORTS
     80 // [SECTION] PLATFORM DEPENDENT HELPERS
     81 // [SECTION] METRICS/DEBUGGER WINDOW
     82 
     83 */
     84 
     85 //-----------------------------------------------------------------------------
     86 // DOCUMENTATION
     87 //-----------------------------------------------------------------------------
     88 
     89 /*
     90 
     91  MISSION STATEMENT
     92  =================
     93 
     94  - Easy to use to create code-driven and data-driven tools.
     95  - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
     96  - Easy to hack and improve.
     97  - Minimize setup and maintenance.
     98  - Minimize state storage on user side.
     99  - Portable, minimize dependencies, run on target (consoles, phones, etc.).
    100  - Efficient runtime and memory consumption.
    101 
    102  Designed for developers and content-creators, not the typical end-user! Some of the current weaknesses includes:
    103 
    104  - Doesn't look fancy, doesn't animate.
    105  - Limited layout features, intricate layouts are typically crafted in code.
    106 
    107 
    108  END-USER GUIDE
    109  ==============
    110 
    111  - Double-click on title bar to collapse window.
    112  - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin().
    113  - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents).
    114  - Click and drag on any empty space to move window.
    115  - TAB/SHIFT+TAB to cycle through keyboard editable fields.
    116  - CTRL+Click on a slider or drag box to input value as text.
    117  - Use mouse wheel to scroll.
    118  - Text editor:
    119    - Hold SHIFT or use mouse to select text.
    120    - CTRL+Left/Right to word jump.
    121    - CTRL+Shift+Left/Right to select words.
    122    - CTRL+A our Double-Click to select all.
    123    - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
    124    - CTRL+Z,CTRL+Y to undo/redo.
    125    - ESCAPE to revert text to its original value.
    126    - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
    127    - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
    128  - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
    129  - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://dearimgui.org/controls_sheets
    130 
    131 
    132  PROGRAMMER GUIDE
    133  ================
    134 
    135  READ FIRST
    136  ----------
    137  - Remember to check the wonderful Wiki (https://github.com/ocornut/imgui/wiki)
    138  - 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 or
    139    destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, fewer bugs.
    140  - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
    141  - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
    142  - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
    143    You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in Wiki.
    144  - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
    145    For every application frame, your UI code will be called only once. This is in contrast to e.g. Unity's implementation of an IMGUI,
    146    where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
    147  - Our origin is on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
    148  - This codebase is also optimized to yield decent performances with typical "Debug" builds settings.
    149  - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
    150    If you get an assert, read the messages and comments around the assert.
    151  - 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.
    152  - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.
    153    See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that.
    154    However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase.
    155  - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!).
    156 
    157 
    158  HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
    159  ----------------------------------------------
    160  - Overwrite all the sources files except for imconfig.h (if you have modified your copy of imconfig.h)
    161  - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over "master".
    162  - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file.
    163  - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
    164    If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
    165    from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
    166    likely be a comment about it. Please report any issue to the GitHub page!
    167  - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file.
    168  - Try to keep your copy of Dear ImGui reasonably up to date.
    169 
    170 
    171  GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
    172  ---------------------------------------------------------------
    173  - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
    174  - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder.
    175  - Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system.
    176    It is recommended you build and statically link the .cpp files as part of your project and NOT as a shared library (DLL).
    177  - 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.
    178  - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
    179  - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
    180    Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
    181    phases of your own application. All rendering information is stored into command-lists that you will retrieve after calling ImGui::Render().
    182  - Refer to the backends and demo applications in the examples/ folder for instruction on how to setup your code.
    183  - 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.
    184 
    185 
    186  HOW A SIMPLE APPLICATION MAY LOOK LIKE
    187  --------------------------------------
    188  EXHIBIT 1: USING THE EXAMPLE BACKENDS (= imgui_impl_XXX.cpp files from the backends/ folder).
    189  The sub-folders in examples/ contain examples applications following this structure.
    190 
    191      // Application init: create a dear imgui context, setup some options, load fonts
    192      ImGui::CreateContext();
    193      ImGuiIO& io = ImGui::GetIO();
    194      // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
    195      // TODO: Fill optional fields of the io structure later.
    196      // TODO: Load TTF/OTF fonts if you don't want to use the default font.
    197 
    198      // Initialize helper Platform and Renderer backends (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp)
    199      ImGui_ImplWin32_Init(hwnd);
    200      ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
    201 
    202      // Application main loop
    203      while (true)
    204      {
    205          // Feed inputs to dear imgui, start new frame
    206          ImGui_ImplDX11_NewFrame();
    207          ImGui_ImplWin32_NewFrame();
    208          ImGui::NewFrame();
    209 
    210          // Any application code here
    211          ImGui::Text("Hello, world!");
    212 
    213          // Render dear imgui into screen
    214          ImGui::Render();
    215          ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
    216          g_pSwapChain->Present(1, 0);
    217      }
    218 
    219      // Shutdown
    220      ImGui_ImplDX11_Shutdown();
    221      ImGui_ImplWin32_Shutdown();
    222      ImGui::DestroyContext();
    223 
    224  EXHIBIT 2: IMPLEMENTING CUSTOM BACKEND / CUSTOM ENGINE
    225 
    226      // Application init: create a dear imgui context, setup some options, load fonts
    227      ImGui::CreateContext();
    228      ImGuiIO& io = ImGui::GetIO();
    229      // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
    230      // TODO: Fill optional fields of the io structure later.
    231      // TODO: Load TTF/OTF fonts if you don't want to use the default font.
    232 
    233      // Build and load the texture atlas into a texture
    234      // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)
    235      int width, height;
    236      unsigned char* pixels = NULL;
    237      io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
    238 
    239      // At this point you've got the texture data and you need to upload that to your graphic system:
    240      // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.
    241      // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID.
    242      MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
    243      io.Fonts->SetTexID((void*)texture);
    244 
    245      // Application main loop
    246      while (true)
    247      {
    248         // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
    249         // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform Backends)
    250         io.DeltaTime = 1.0f/60.0f;              // set the time elapsed since the previous frame (in seconds)
    251         io.DisplaySize.x = 1920.0f;             // set the current display width
    252         io.DisplaySize.y = 1280.0f;             // set the current display height here
    253         io.MousePos = my_mouse_pos;             // set the mouse position
    254         io.MouseDown[0] = my_mouse_buttons[0];  // set the mouse button states
    255         io.MouseDown[1] = my_mouse_buttons[1];
    256 
    257         // Call NewFrame(), after this point you can use ImGui::* functions anytime
    258         // (So you want to try calling NewFrame() as early as you can in your main loop to be able to use Dear ImGui everywhere)
    259         ImGui::NewFrame();
    260 
    261         // Most of your application code here
    262         ImGui::Text("Hello, world!");
    263         MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
    264         MyGameRender(); // may use any Dear ImGui functions as well!
    265 
    266         // Render dear imgui, swap buffers
    267         // (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)
    268         ImGui::EndFrame();
    269         ImGui::Render();
    270         ImDrawData* draw_data = ImGui::GetDrawData();
    271         MyImGuiRenderFunction(draw_data);
    272         SwapBuffers();
    273      }
    274 
    275      // Shutdown
    276      ImGui::DestroyContext();
    277 
    278  To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest of your application,
    279  you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
    280  Please read the FAQ and example applications for details about this!
    281 
    282 
    283  HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
    284  ---------------------------------------------
    285  The backends in impl_impl_XXX.cpp files contain many working implementations of a rendering function.
    286 
    287     void void MyImGuiRenderFunction(ImDrawData* draw_data)
    288     {
    289        // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
    290        // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
    291        // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
    292        // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
    293        for (int n = 0; n < draw_data->CmdListsCount; n++)
    294        {
    295           const ImDrawList* cmd_list = draw_data->CmdLists[n];
    296           const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;  // vertex buffer generated by Dear ImGui
    297           const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;   // index buffer generated by Dear ImGui
    298           for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
    299           {
    300              const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
    301              if (pcmd->UserCallback)
    302              {
    303                  pcmd->UserCallback(cmd_list, pcmd);
    304              }
    305              else
    306              {
    307                  // The texture for the draw call is specified by pcmd->GetTexID().
    308                  // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.
    309                  MyEngineBindTexture((MyTexture*)pcmd->GetTexID());
    310 
    311                  // We are using scissoring to clip some objects. All low-level graphics API should support it.
    312                  // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
    313                  //   (some elements visible outside their bounds) but you can fix that once everything else works!
    314                  // - Clipping coordinates are provided in imgui coordinates space:
    315                  //   - For a given viewport, draw_data->DisplayPos == viewport->Pos and draw_data->DisplaySize == viewport->Size
    316                  //   - In a single viewport application, draw_data->DisplayPos == (0,0) and draw_data->DisplaySize == io.DisplaySize, but always use GetMainViewport()->Pos/Size instead of hardcoding those values.
    317                  //   - In the interest of supporting multi-viewport applications (see 'docking' branch on github),
    318                  //     always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.
    319                  // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)
    320                  ImVec2 pos = draw_data->DisplayPos;
    321                  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));
    322 
    323                  // Render 'pcmd->ElemCount/3' indexed triangles.
    324                  // 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.
    325                  MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
    326              }
    327              idx_buffer += pcmd->ElemCount;
    328           }
    329        }
    330     }
    331 
    332 
    333  USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
    334  ------------------------------------------
    335  - The gamepad/keyboard navigation is fairly functional and keeps being improved.
    336  - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse!
    337  - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787
    338  - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
    339  - Keyboard:
    340     - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
    341       NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
    342     - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag
    343       will be set. For more advanced uses, you may want to read from:
    344        - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
    345        - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
    346        - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
    347       Please reach out if you think the game vs navigation input sharing could be improved.
    348  - Gamepad:
    349     - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
    350     - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame().
    351       Note that io.NavInputs[] is cleared by EndFrame().
    352     - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
    353          0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
    354     - We use a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
    355       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.).
    356     - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets
    357     - 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
    358       to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
    359  - Mouse:
    360     - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
    361     - 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.
    362     - 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.
    363       Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
    364       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.
    365       When that happens your backend NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the backends in examples/ do that.
    366       (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse moving back and forth!)
    367       (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
    368        to set a boolean to ignore your other external mouse positions until the external source is moved again.)
    369 
    370 
    371  API BREAKING CHANGES
    372  ====================
    373 
    374  Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
    375  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.
    376  When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
    377  You can read releases logs https://github.com/ocornut/imgui/releases for more details.
    378 
    379  - 2021/05/19 (1.83) - backends: obsoleted direct access to ImDrawCmd::TextureId in favor of calling ImDrawCmd::GetTexID().
    380                         - if you are using official backends from the source tree: you have nothing to do.
    381                         - if you have copied old backend code or using your own: change access to draw_cmd->TextureId to draw_cmd->GetTexID().
    382  - 2021/03/12 (1.82) - upgraded ImDrawList::AddRect(), AddRectFilled(), PathRect() to use ImDrawFlags instead of ImDrawCornersFlags.
    383                         - ImDrawCornerFlags_TopLeft  -> use ImDrawFlags_RoundCornersTopLeft
    384                         - ImDrawCornerFlags_BotRight -> use ImDrawFlags_RoundCornersBottomRight
    385                         - ImDrawCornerFlags_None     -> use ImDrawFlags_RoundCornersNone etc.
    386                        flags now sanely defaults to 0 instead of 0x0F, consistent with all other flags in the API.
    387                        breaking: the default with rounding > 0.0f is now "round all corners" vs old implicit "round no corners":
    388                         - rounding == 0.0f + flags == 0 --> meant no rounding  --> unchanged (common use)
    389                         - rounding  > 0.0f + flags != 0 --> meant rounding     --> unchanged (common use)
    390                         - rounding == 0.0f + flags != 0 --> meant no rounding  --> unchanged (unlikely use)
    391                         - rounding  > 0.0f + flags == 0 --> meant no rounding  --> BREAKING (unlikely use): will now round all corners --> use ImDrawFlags_RoundCornersNone or rounding == 0.0f.
    392                        this ONLY matters for hard coded use of 0 + rounding > 0.0f. Use of named ImDrawFlags_RoundCornersNone (new) or ImDrawCornerFlags_None (old) are ok.
    393                        the old ImDrawCornersFlags used awkward default values of ~0 or 0xF (4 lower bits set) to signify "round all corners" and we sometimes encouraged using them as shortcuts.
    394                        legacy path still support use of hard coded ~0 or any value from 0x1 or 0xF. They will behave the same with legacy paths enabled (will assert otherwise).
    395  - 2021/03/11 (1.82) - removed redirecting functions/enums names that were marked obsolete in 1.66 (September 2018):
    396                         - ImGui::SetScrollHere()              -> use ImGui::SetScrollHereY()
    397  - 2021/03/11 (1.82) - clarified that ImDrawList::PathArcTo(), ImDrawList::PathArcToFast() won't render with radius < 0.0f. Previously it sorts of accidentally worked but would generally lead to counter-clockwise paths and have an effect on anti-aliasing.
    398  - 2021/03/10 (1.82) - upgraded ImDrawList::AddPolyline() and PathStroke() "bool closed" parameter to "ImDrawFlags flags". The matching ImDrawFlags_Closed value is guaranteed to always stay == 1 in the future.
    399  - 2021/02/22 (1.82) - win32+mingw: Re-enabled IME functions by default even under MinGW. In July 2016, issue #738 had me incorrectly disable those default functions for MinGW. MinGW users should: either link with -limm32, either set their imconfig file  with '#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS'.
    400  - 2021/02/17 (1.82) - renamed rarely used style.CircleSegmentMaxError (old default = 1.60f) to style.CircleTessellationMaxError (new default = 0.30f) as the meaning of the value changed.
    401  - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete).
    402                      - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete).
    403                      - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete).
    404  - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags.
    405                      - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags.
    406                      - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API.
    407  - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018):
    408                         - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit().
    409                         - ImGuiCol_ModalWindowDarkening       -> use ImGuiCol_ModalWindowDimBg
    410                         - ImGuiInputTextCallback              -> use ImGuiTextEditCallback
    411                         - ImGuiInputTextCallbackData          -> use ImGuiTextEditCallbackData
    412  - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete).
    413  - 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added!
    414  - 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API.
    415  - 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures
    416  - 2020/10/14 (1.80) - backends: moved all backends files (imgui_impl_XXXX.cpp, imgui_impl_XXXX.h) from examples/ to backends/.
    417  - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.60 (April 2018):
    418                         - io.RenderDrawListsFn pointer        -> use ImGui::GetDrawData() value and call the render function of your backend
    419                         - ImGui::IsAnyWindowFocused()         -> use ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow)
    420                         - ImGui::IsAnyWindowHovered()         -> use ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
    421                         - ImGuiStyleVar_Count_                -> use ImGuiStyleVar_COUNT
    422                         - ImGuiMouseCursor_Count_             -> use ImGuiMouseCursor_COUNT
    423                       - removed redirecting functions names that were marked obsolete in 1.61 (May 2018):
    424                         - InputFloat (... int decimal_precision ...) -> use InputFloat (... const char* format ...) with format = "%.Xf" where X is your value for decimal_precision.
    425                         - same for InputFloat2()/InputFloat3()/InputFloat4() variants taking a `int decimal_precision` parameter.
    426  - 2020/10/05 (1.79) - removed ImGuiListClipper: Renamed constructor parameters which created an ambiguous alternative to using the ImGuiListClipper::Begin() function, with misleading edge cases (note: imgui_memory_editor <0.40 from imgui_club/ used this old clipper API. Update your copy if needed).
    427  - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently).
    428  - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton.
    429  - 2020/09/21 (1.79) - renamed OpenPopupContextItem() back to OpenPopupOnItemClick(), reverting the change from 1.77. For varieties of reason this is more self-explanatory.
    430  - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on an item - because it is inconsistent with other popup APIs and makes others misleading. It's also and unnecessary: you can use IsWindowAppearing() after BeginPopup() for a similar result.
    431  - 2020/09/17 (1.79) - removed ImFont::DisplayOffset in favor of ImFontConfig::GlyphOffset. DisplayOffset was applied after scaling and not very meaningful/useful outside of being needed by the default ProggyClean font. If you scaled this value after calling AddFontDefault(), this is now done automatically. It was also getting in the way of better font scaling, so let's get rid of it now!
    432  - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().
    433                        replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
    434                        worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:
    435                        - if you omitted the 'power' parameter (likely!), you are not affected.
    436                        - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct.
    437                        - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.
    438                        see https://github.com/ocornut/imgui/issues/3361 for all details.
    439                        kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version was removed directly as they were most unlikely ever used.
    440                        for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
    441                      - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime.
    442  - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
    443  - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79]
    444  - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.
    445  - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular().
    446  - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.
    447  - 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.
    448  - 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.
    449  - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017):
    450                        - ShowTestWindow()                    -> use ShowDemoWindow()
    451                        - IsRootWindowFocused()               -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)
    452                        - IsRootWindowOrAnyChildFocused()     -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
    453                        - SetNextWindowContentWidth(w)        -> use SetNextWindowContentSize(ImVec2(w, 0.0f)
    454                        - GetItemsLineHeightWithSpacing()     -> use GetFrameHeightWithSpacing()
    455                        - ImGuiCol_ChildWindowBg              -> use ImGuiCol_ChildBg
    456                        - ImGuiStyleVar_ChildWindowRounding   -> use ImGuiStyleVar_ChildRounding
    457                        - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap
    458                        - IMGUI_DISABLE_TEST_WINDOWS          -> use IMGUI_DISABLE_DEMO_WINDOWS
    459  - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was vaguely documented and rarely if ever used). Instead, we added an explicit PrimUnreserve() API.
    460  - 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).
    461  - 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.
    462  - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
    463  - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.
    464  - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017):
    465                        - Begin() [old 5 args version]        -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed
    466                        - IsRootWindowOrAnyChildHovered()     -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows)
    467                        - AlignFirstTextHeightToWidgets()     -> use AlignTextToFramePadding()
    468                        - SetNextWindowPosCenter()            -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f)
    469                        - ImFont::Glyph                       -> use ImFontGlyph
    470  - 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.
    471                        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.
    472                        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).
    473                        If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.
    474  - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
    475  - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
    476  - 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.
    477  - 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
    478                        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.
    479                        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.
    480                        Please reach out if you are affected.
    481  - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
    482  - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
    483  - 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.
    484  - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
    485  - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
    486  - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).
    487  - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrarily small value!
    488  - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
    489  - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
    490  - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
    491  - 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.
    492  - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
    493  - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
    494  - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
    495  - 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.
    496                        If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
    497  - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
    498  - 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.
    499                        NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.
    500                        Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.
    501  - 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).
    502  - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
    503  - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
    504  - 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.
    505  - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
    506  - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
    507  - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
    508  - 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.).
    509                        old backends will still work as is, however prefer using the separated backends as they will be updated to support multi-viewports.
    510                        when adopting new backends follow the main.cpp code of your preferred examples/ folder to know which functions to call.
    511                        in particular, note that old backends called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function.
    512  - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
    513  - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
    514  - 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.
    515                        If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
    516                        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.
    517                        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.
    518  - 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",
    519                        consistent with other functions. Kept redirection functions (will obsolete).
    520  - 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.
    521  - 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 backend ahead of merging the Nav branch).
    522  - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
    523  - 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.
    524  - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
    525  - 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.
    526  - 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.
    527  - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
    528                        - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
    529                        - removed Shutdown() function, as DestroyContext() serve this purpose.
    530                        - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
    531                        - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
    532                        - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
    533  - 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.
    534  - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
    535  - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
    536  - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
    537  - 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.
    538  - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
    539  - 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
    540  - 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.
    541  - 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.
    542  - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
    543  - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
    544                      - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
    545  - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
    546  - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
    547  - 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.
    548  - 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.
    549                        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.
    550  - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
    551  - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
    552  - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
    553  - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
    554  - 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.
    555  - 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.
    556  - 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.
    557                        removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
    558                          IsItemHoveredRect()        --> IsItemHovered(ImGuiHoveredFlags_RectOnly)
    559                          IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
    560                          IsMouseHoveringWindow()    --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]
    561  - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
    562  - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
    563  - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).
    564  - 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).
    565  - 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 backend if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
    566  - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
    567                      - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
    568                      - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
    569  - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
    570  - 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.
    571  - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.
    572  - 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.
    573  - 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).
    574  - 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).
    575  - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
    576  - 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.
    577                      - 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.
    578                      - 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))'
    579  - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
    580  - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
    581  - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
    582  - 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().
    583  - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
    584  - 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.
    585  - 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.
    586  - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
    587                        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 to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
    588                        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:
    589                        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); }
    590                        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.
    591  - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
    592  - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
    593  - 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).
    594  - 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.
    595  - 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).
    596  - 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)
    597  - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
    598  - 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.
    599  - 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.
    600  - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
    601  - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
    602  - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
    603                        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.
    604                        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!
    605  - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
    606  - 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.
    607  - 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
    608  - 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.
    609                        you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
    610  - 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.
    611                        this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
    612                      - if you are using a vanilla copy of one of the imgui_impl_XXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
    613                      - the signature of the io.RenderDrawListsFn handler has changed!
    614                        old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
    615                        new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
    616                          parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
    617                          ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
    618                          ImDrawCmd:  'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
    619                      - 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.
    620                      - 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!
    621                      - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
    622  - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
    623  - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
    624  - 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.
    625  - 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
    626  - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely used. Sorry!
    627  - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
    628  - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
    629  - 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.
    630  - 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.
    631  - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
    632  - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
    633  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
    634  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
    635  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
    636  - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
    637  - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
    638  - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
    639  - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
    640  - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
    641  - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
    642  - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
    643  - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
    644  - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
    645  - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
    646  - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
    647  - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
    648  - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
    649                        - old:  const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..];
    650                        - new:  unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier);
    651                        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.
    652  - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID()
    653  - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
    654  - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
    655  - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
    656  - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
    657  - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
    658  - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
    659  - 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)
    660  - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
    661  - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
    662  - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
    663  - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
    664  - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
    665  - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
    666 
    667 
    668  FREQUENTLY ASKED QUESTIONS (FAQ)
    669  ================================
    670 
    671  Read all answers online:
    672    https://www.dearimgui.org/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url)
    673  Read all answers locally (with a text editor or ideally a Markdown viewer):
    674    docs/FAQ.md
    675  Some answers are copied down here to facilitate searching in code.
    676 
    677  Q&A: Basics
    678  ===========
    679 
    680  Q: Where is the documentation?
    681  A: This library is poorly documented at the moment and expects the user to be acquainted with C/C++.
    682     - Run the examples/ and explore them.
    683     - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
    684     - The demo covers most features of Dear ImGui, so you can read the code and see its output.
    685     - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
    686     - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the
    687       examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
    688     - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.
    689     - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.
    690     - Your programming IDE is your friend, find the type or function declaration to find comments
    691       associated with it.
    692 
    693  Q: What is this library called?
    694  Q: Which version should I get?
    695  >> This library is called "Dear ImGui", please don't call it "ImGui" :)
    696  >> See https://www.dearimgui.org/faq for details.
    697 
    698  Q&A: Integration
    699  ================
    700 
    701  Q: How to get started?
    702  A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt.
    703 
    704  Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?
    705  A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
    706  >> See https://www.dearimgui.org/faq for a fully detailed answer. You really want to read this.
    707 
    708  Q. How can I enable keyboard controls?
    709  Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
    710  Q: I integrated Dear ImGui in my engine and little squares are showing instead of text...
    711  Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...
    712  Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...
    713  >> See https://www.dearimgui.org/faq
    714 
    715  Q&A: Usage
    716  ----------
    717 
    718  Q: Why is my widget not reacting when I click on it?
    719  Q: How can I have widgets with an empty label?
    720  Q: How can I have multiple widgets with the same label?
    721  Q: How can I display an image? What is ImTextureID, how does it works?
    722  Q: How can I use my own math types instead of ImVec2/ImVec4?
    723  Q: How can I interact with standard C++ types (such as std::string and std::vector)?
    724  Q: How can I display custom shapes? (using low-level ImDrawList API)
    725  >> See https://www.dearimgui.org/faq
    726 
    727  Q&A: Fonts, Text
    728  ================
    729 
    730  Q: How should I handle DPI in my application?
    731  Q: How can I load a different font than the default?
    732  Q: How can I easily use icons in my application?
    733  Q: How can I load multiple fonts?
    734  Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
    735  >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md
    736 
    737  Q&A: Concerns
    738  =============
    739 
    740  Q: Who uses Dear ImGui?
    741  Q: Can you create elaborate/serious tools with Dear ImGui?
    742  Q: Can you reskin the look of Dear ImGui?
    743  Q: Why using C++ (as opposed to C)?
    744  >> See https://www.dearimgui.org/faq
    745 
    746  Q&A: Community
    747  ==============
    748 
    749  Q: How can I help?
    750  A: - Businesses: please reach out to "contact AT dearimgui.com" if you work in a place using Dear ImGui!
    751       We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
    752       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.
    753     - Individuals: you can support continued development via PayPal donations. See README.
    754     - If you are experienced with Dear ImGui and C++, look at the GitHub issues, look at the Wiki, read docs/TODO.txt
    755       and see how you want to help and can help!
    756     - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
    757       You may post screenshot or links in the gallery threads. Visuals are ideal as they inspire other programmers.
    758       But even without visuals, disclosing your use of dear imgui helps the library grow credibility, and help other teams and programmers with taking decisions.
    759     - 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).
    760 
    761 */
    762 
    763 //-------------------------------------------------------------------------
    764 // [SECTION] INCLUDES
    765 //-------------------------------------------------------------------------
    766 
    767 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
    768 #define _CRT_SECURE_NO_WARNINGS
    769 #endif
    770 
    771 #include "imgui.h"
    772 #ifndef IMGUI_DISABLE
    773 
    774 #ifndef IMGUI_DEFINE_MATH_OPERATORS
    775 #define IMGUI_DEFINE_MATH_OPERATORS
    776 #endif
    777 #include "imgui_internal.h"
    778 
    779 // System includes
    780 #include <ctype.h>      // toupper
    781 #include <stdio.h>      // vsnprintf, sscanf, printf
    782 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
    783 #include <stddef.h>     // intptr_t
    784 #else
    785 #include <stdint.h>     // intptr_t
    786 #endif
    787 
    788 // [Windows] OS specific includes (optional)
    789 #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)
    790 #define IMGUI_DISABLE_WIN32_FUNCTIONS
    791 #endif
    792 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
    793 #ifndef WIN32_LEAN_AND_MEAN
    794 #define WIN32_LEAN_AND_MEAN
    795 #endif
    796 #ifndef NOMINMAX
    797 #define NOMINMAX
    798 #endif
    799 #include <windows.h>
    800 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions
    801 #define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
    802 #define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
    803 #endif
    804 #endif
    805 
    806 // [Apple] OS specific includes
    807 #if defined(__APPLE__)
    808 #include <TargetConditionals.h>
    809 #endif
    810 
    811 // Visual Studio warnings
    812 #ifdef _MSC_VER
    813 #pragma warning (disable: 4127)             // condition expression is constant
    814 #pragma warning (disable: 4996)             // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
    815 #if defined(_MSC_VER) && _MSC_VER >= 1922   // MSVC 2019 16.2 or later
    816 #pragma warning (disable: 5054)             // operator '|': deprecated between enumerations of different types
    817 #endif
    818 #pragma warning (disable: 26451)            // [Static Analyzer] Arithmetic overflow : Using operator 'xxx' on a 4 byte value and then casting the result to a 8 byte value. Cast the value to the wider type before calling operator 'xxx' to avoid overflow(io.2).
    819 #pragma warning (disable: 26495)            // [Static Analyzer] Variable 'XXX' is uninitialized. Always initialize a member variable (type.6).
    820 #pragma warning (disable: 26812)            // [Static Analyzer] The enum type 'xxx' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
    821 #endif
    822 
    823 // Clang/GCC warnings with -Weverything
    824 #if defined(__clang__)
    825 #if __has_warning("-Wunknown-warning-option")
    826 #pragma clang diagnostic ignored "-Wunknown-warning-option"         // warning: unknown warning group 'xxx'                      // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
    827 #endif
    828 #pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
    829 #pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                            // yes, they are more terse.
    830 #pragma clang diagnostic ignored "-Wfloat-equal"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
    831 #pragma clang diagnostic ignored "-Wformat-nonliteral"              // warning: format string is not a string literal            // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
    832 #pragma clang diagnostic ignored "-Wexit-time-destructors"          // warning: declaration requires an exit-time destructor     // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
    833 #pragma clang diagnostic ignored "-Wglobal-constructors"            // warning: declaration requires a global destructor         // similar to above, not sure what the exact difference is.
    834 #pragma clang diagnostic ignored "-Wsign-conversion"                // warning: implicit conversion changes signedness
    835 #pragma clang diagnostic ignored "-Wformat-pedantic"                // warning: format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.
    836 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning: cast to 'void *' from smaller integer type 'int'
    837 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0
    838 #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.
    839 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
    840 #elif defined(__GNUC__)
    841 // We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association.
    842 #pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
    843 #pragma GCC diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
    844 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"      // warning: cast to pointer from integer of different size
    845 #pragma GCC diagnostic ignored "-Wformat"                   // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
    846 #pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
    847 #pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
    848 #pragma GCC diagnostic ignored "-Wformat-nonliteral"        // warning: format not a string literal, format string not checked
    849 #pragma GCC diagnostic ignored "-Wstrict-overflow"          // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
    850 #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
    851 #endif
    852 
    853 // Debug options
    854 #define IMGUI_DEBUG_NAV_SCORING     0   // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL
    855 #define IMGUI_DEBUG_NAV_RECTS       0   // Display the reference navigation rectangle for each window
    856 #define IMGUI_DEBUG_INI_SETTINGS    0   // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower)
    857 
    858 // 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.
    859 static const float NAV_WINDOWING_HIGHLIGHT_DELAY            = 0.20f;    // Time before the highlight and screen dimming starts fading in
    860 static const float NAV_WINDOWING_LIST_APPEAR_DELAY          = 0.15f;    // Time before the window list starts to appear
    861 
    862 // Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by backend)
    863 static const float WINDOWS_HOVER_PADDING                    = 4.0f;     // Extend outside window for hovering/resizing (maxxed with TouchPadding) and inside windows for borders. Affect FindHoveredWindow().
    864 static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f;    // Reduce visual noise by only highlighting the border after a certain time.
    865 static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER    = 2.00f;    // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
    866 
    867 //-------------------------------------------------------------------------
    868 // [SECTION] FORWARD DECLARATIONS
    869 //-------------------------------------------------------------------------
    870 
    871 static void             SetCurrentWindow(ImGuiWindow* window);
    872 static void             FindHoveredWindow();
    873 static ImGuiWindow*     CreateNewWindow(const char* name, ImGuiWindowFlags flags);
    874 static ImVec2           CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);
    875 
    876 static void             AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
    877 static void             AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
    878 
    879 // Settings
    880 static void             WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);
    881 static void*            WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
    882 static void             WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
    883 static void             WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
    884 static void             WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
    885 
    886 // Platform Dependents default implementation for IO functions
    887 static const char*      GetClipboardTextFn_DefaultImpl(void* user_data);
    888 static void             SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
    889 static void             ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
    890 
    891 namespace ImGui
    892 {
    893 // Navigation
    894 static void             NavUpdate();
    895 static void             NavUpdateWindowing();
    896 static void             NavUpdateWindowingOverlay();
    897 static void             NavUpdateMoveResult();
    898 static void             NavUpdateInitResult();
    899 static float            NavUpdatePageUpPageDown();
    900 static inline void      NavUpdateAnyRequestFlag();
    901 static void             NavEndFrame();
    902 static bool             NavScoreItem(ImGuiNavItemData* result, ImRect cand);
    903 static void             NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel);
    904 static void             NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
    905 static ImVec2           NavCalcPreferredRefPos();
    906 static void             NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
    907 static ImGuiWindow*     NavRestoreLastChildNavWindow(ImGuiWindow* window);
    908 static void             NavRestoreLayer(ImGuiNavLayer layer);
    909 static int              FindWindowFocusIndex(ImGuiWindow* window);
    910 
    911 // Error Checking
    912 static void             ErrorCheckNewFrameSanityChecks();
    913 static void             ErrorCheckEndFrameSanityChecks();
    914 
    915 // Misc
    916 static void             UpdateSettings();
    917 static void             UpdateMouseInputs();
    918 static void             UpdateMouseWheel();
    919 static void             UpdateTabFocus();
    920 static void             UpdateDebugToolItemPicker();
    921 static bool             UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect);
    922 static void             RenderWindowOuterBorders(ImGuiWindow* window);
    923 static void             RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
    924 static void             RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
    925 
    926 // Viewports
    927 static void             UpdateViewportsNewFrame();
    928 
    929 }
    930 
    931 //-----------------------------------------------------------------------------
    932 // [SECTION] CONTEXT AND MEMORY ALLOCATORS
    933 //-----------------------------------------------------------------------------
    934 
    935 // DLL users:
    936 // - Heaps and globals are not shared across DLL boundaries!
    937 // - You will need to call SetCurrentContext() + SetAllocatorFunctions() for each static/DLL boundary you are calling from.
    938 // - Same applies for hot-reloading mechanisms that are reliant on reloading DLL (note that many hot-reloading mechanisms work without DLL).
    939 // - Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
    940 // - Confused? In a debugger: add GImGui to your watch window and notice how its value changes depending on your current location (which DLL boundary you are in).
    941 
    942 // Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
    943 // - ImGui::CreateContext() will automatically set this pointer if it is NULL.
    944 //   Change to a different context by calling ImGui::SetCurrentContext().
    945 // - Important: Dear ImGui functions are not thread-safe because of this pointer.
    946 //   If you want thread-safety to allow N threads to access N different contexts:
    947 //   - Change this variable to use thread local storage so each thread can refer to a different context, in your imconfig.h:
    948 //         struct ImGuiContext;
    949 //         extern thread_local ImGuiContext* MyImGuiTLS;
    950 //         #define GImGui MyImGuiTLS
    951 //     And then define MyImGuiTLS in one of your cpp files. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
    952 //   - Future development aims to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
    953 //   - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from a different namespace.
    954 // - DLL users: read comments above.
    955 #ifndef GImGui
    956 ImGuiContext*   GImGui = NULL;
    957 #endif
    958 
    959 // Memory Allocator functions. Use SetAllocatorFunctions() to change them.
    960 // - You probably don't want to modify that mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
    961 // - DLL users: read comments above.
    962 #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
    963 static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); return malloc(size); }
    964 static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); free(ptr); }
    965 #else
    966 static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
    967 static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
    968 #endif
    969 static ImGuiMemAllocFunc    GImAllocatorAllocFunc = MallocWrapper;
    970 static ImGuiMemFreeFunc     GImAllocatorFreeFunc = FreeWrapper;
    971 static void*                GImAllocatorUserData = NULL;
    972 
    973 //-----------------------------------------------------------------------------
    974 // [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
    975 //-----------------------------------------------------------------------------
    976 
    977 ImGuiStyle::ImGuiStyle()
    978 {
    979     Alpha                   = 1.0f;             // Global alpha applies to everything in ImGui
    980     WindowPadding           = ImVec2(8,8);      // Padding within a window
    981     WindowRounding          = 0.0f;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
    982     WindowBorderSize        = 1.0f;             // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
    983     WindowMinSize           = ImVec2(32,32);    // Minimum window size
    984     WindowTitleAlign        = ImVec2(0.0f,0.5f);// Alignment for title bar text
    985     WindowMenuButtonPosition= ImGuiDir_Left;    // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
    986     ChildRounding           = 0.0f;             // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
    987     ChildBorderSize         = 1.0f;             // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
    988     PopupRounding           = 0.0f;             // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
    989     PopupBorderSize         = 1.0f;             // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
    990     FramePadding            = ImVec2(4,3);      // Padding within a framed rectangle (used by most widgets)
    991     FrameRounding           = 0.0f;             // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
    992     FrameBorderSize         = 0.0f;             // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
    993     ItemSpacing             = ImVec2(8,4);      // Horizontal and vertical spacing between widgets/lines
    994     ItemInnerSpacing        = ImVec2(4,4);      // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
    995     CellPadding             = ImVec2(4,2);      // Padding within a table cell
    996     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!
    997     IndentSpacing           = 21.0f;            // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
    998     ColumnsMinSpacing       = 6.0f;             // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
    999     ScrollbarSize           = 14.0f;            // Width of the vertical scrollbar, Height of the horizontal scrollbar
   1000     ScrollbarRounding       = 9.0f;             // Radius of grab corners rounding for scrollbar
   1001     GrabMinSize             = 10.0f;            // Minimum width/height of a grab box for slider/scrollbar
   1002     GrabRounding            = 0.0f;             // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
   1003     LogSliderDeadzone       = 4.0f;             // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
   1004     TabRounding             = 4.0f;             // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
   1005     TabBorderSize           = 0.0f;             // Thickness of border around tabs.
   1006     TabMinWidthForCloseButton = 0.0f;           // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
   1007     ColorButtonPosition     = ImGuiDir_Right;   // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
   1008     ButtonTextAlign         = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
   1009     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.
   1010     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.
   1011     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.
   1012     MouseCursorScale        = 1.0f;             // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
   1013     AntiAliasedLines        = true;             // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
   1014     AntiAliasedLinesUseTex  = true;             // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering.
   1015     AntiAliasedFill         = true;             // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
   1016     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.
   1017     CircleTessellationMaxError = 0.30f;         // 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.
   1018 
   1019     // Default theme
   1020     ImGui::StyleColorsDark(this);
   1021 }
   1022 
   1023 // 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.
   1024 // 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.
   1025 void ImGuiStyle::ScaleAllSizes(float scale_factor)
   1026 {
   1027     WindowPadding = ImFloor(WindowPadding * scale_factor);
   1028     WindowRounding = ImFloor(WindowRounding * scale_factor);
   1029     WindowMinSize = ImFloor(WindowMinSize * scale_factor);
   1030     ChildRounding = ImFloor(ChildRounding * scale_factor);
   1031     PopupRounding = ImFloor(PopupRounding * scale_factor);
   1032     FramePadding = ImFloor(FramePadding * scale_factor);
   1033     FrameRounding = ImFloor(FrameRounding * scale_factor);
   1034     ItemSpacing = ImFloor(ItemSpacing * scale_factor);
   1035     ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
   1036     CellPadding = ImFloor(CellPadding * scale_factor);
   1037     TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
   1038     IndentSpacing = ImFloor(IndentSpacing * scale_factor);
   1039     ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
   1040     ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
   1041     ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
   1042     GrabMinSize = ImFloor(GrabMinSize * scale_factor);
   1043     GrabRounding = ImFloor(GrabRounding * scale_factor);
   1044     LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor);
   1045     TabRounding = ImFloor(TabRounding * scale_factor);
   1046     TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX;
   1047     DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
   1048     DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
   1049     MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
   1050 }
   1051 
   1052 ImGuiIO::ImGuiIO()
   1053 {
   1054     // Most fields are initialized with zero
   1055     memset(this, 0, sizeof(*this));
   1056     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.
   1057 
   1058     // Settings
   1059     ConfigFlags = ImGuiConfigFlags_None;
   1060     BackendFlags = ImGuiBackendFlags_None;
   1061     DisplaySize = ImVec2(-1.0f, -1.0f);
   1062     DeltaTime = 1.0f / 60.0f;
   1063     IniSavingRate = 5.0f;
   1064     IniFilename = "imgui.ini";
   1065     LogFilename = "imgui_log.txt";
   1066     MouseDoubleClickTime = 0.30f;
   1067     MouseDoubleClickMaxDist = 6.0f;
   1068     for (int i = 0; i < ImGuiKey_COUNT; i++)
   1069         KeyMap[i] = -1;
   1070     KeyRepeatDelay = 0.275f;
   1071     KeyRepeatRate = 0.050f;
   1072     UserData = NULL;
   1073 
   1074     Fonts = NULL;
   1075     FontGlobalScale = 1.0f;
   1076     FontDefault = NULL;
   1077     FontAllowUserScaling = false;
   1078     DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
   1079 
   1080     // Miscellaneous options
   1081     MouseDrawCursor = false;
   1082 #ifdef __APPLE__
   1083     ConfigMacOSXBehaviors = true;  // Set Mac OS X style defaults based on __APPLE__ compile time flag
   1084 #else
   1085     ConfigMacOSXBehaviors = false;
   1086 #endif
   1087     ConfigInputTextCursorBlink = true;
   1088     ConfigWindowsResizeFromEdges = true;
   1089     ConfigWindowsMoveFromTitleBarOnly = false;
   1090     ConfigMemoryCompactTimer = 60.0f;
   1091 
   1092     // Platform Functions
   1093     BackendPlatformName = BackendRendererName = NULL;
   1094     BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
   1095     GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;   // Platform dependent default implementations
   1096     SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
   1097     ClipboardUserData = NULL;
   1098     ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
   1099     ImeWindowHandle = NULL;
   1100 
   1101     // Input (NB: we already have memset zero the entire structure!)
   1102     MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
   1103     MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
   1104     MouseDragThreshold = 6.0f;
   1105     for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
   1106     for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i]  = KeysDownDurationPrev[i] = -1.0f;
   1107     for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
   1108 }
   1109 
   1110 // Pass in translated ASCII characters for text input.
   1111 // - with glfw you can get those from the callback set in glfwSetCharCallback()
   1112 // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
   1113 void ImGuiIO::AddInputCharacter(unsigned int c)
   1114 {
   1115     if (c != 0)
   1116         InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
   1117 }
   1118 
   1119 // UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
   1120 // we should save the high surrogate.
   1121 void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
   1122 {
   1123     if (c == 0 && InputQueueSurrogate == 0)
   1124         return;
   1125 
   1126     if ((c & 0xFC00) == 0xD800) // High surrogate, must save
   1127     {
   1128         if (InputQueueSurrogate != 0)
   1129             InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
   1130         InputQueueSurrogate = c;
   1131         return;
   1132     }
   1133 
   1134     ImWchar cp = c;
   1135     if (InputQueueSurrogate != 0)
   1136     {
   1137         if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
   1138         {
   1139             InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
   1140         }
   1141         else
   1142         {
   1143 #if IM_UNICODE_CODEPOINT_MAX == 0xFFFF
   1144             cp = IM_UNICODE_CODEPOINT_INVALID; // Codepoint will not fit in ImWchar
   1145 #else
   1146             cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
   1147 #endif
   1148         }
   1149 
   1150         InputQueueSurrogate = 0;
   1151     }
   1152     InputQueueCharacters.push_back(cp);
   1153 }
   1154 
   1155 void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
   1156 {
   1157     while (*utf8_chars != 0)
   1158     {
   1159         unsigned int c = 0;
   1160         utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
   1161         if (c != 0)
   1162             InputQueueCharacters.push_back((ImWchar)c);
   1163     }
   1164 }
   1165 
   1166 void ImGuiIO::ClearInputCharacters()
   1167 {
   1168     InputQueueCharacters.resize(0);
   1169 }
   1170 
   1171 //-----------------------------------------------------------------------------
   1172 // [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
   1173 //-----------------------------------------------------------------------------
   1174 
   1175 ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
   1176 {
   1177     IM_ASSERT(num_segments > 0); // Use ImBezierCubicClosestPointCasteljau()
   1178     ImVec2 p_last = p1;
   1179     ImVec2 p_closest;
   1180     float p_closest_dist2 = FLT_MAX;
   1181     float t_step = 1.0f / (float)num_segments;
   1182     for (int i_step = 1; i_step <= num_segments; i_step++)
   1183     {
   1184         ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step);
   1185         ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
   1186         float dist2 = ImLengthSqr(p - p_line);
   1187         if (dist2 < p_closest_dist2)
   1188         {
   1189             p_closest = p_line;
   1190             p_closest_dist2 = dist2;
   1191         }
   1192         p_last = p_current;
   1193     }
   1194     return p_closest;
   1195 }
   1196 
   1197 // Closely mimics PathBezierToCasteljau() in imgui_draw.cpp
   1198 static void ImBezierCubicClosestPointCasteljauStep(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)
   1199 {
   1200     float dx = x4 - x1;
   1201     float dy = y4 - y1;
   1202     float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
   1203     float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
   1204     d2 = (d2 >= 0) ? d2 : -d2;
   1205     d3 = (d3 >= 0) ? d3 : -d3;
   1206     if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
   1207     {
   1208         ImVec2 p_current(x4, y4);
   1209         ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
   1210         float dist2 = ImLengthSqr(p - p_line);
   1211         if (dist2 < p_closest_dist2)
   1212         {
   1213             p_closest = p_line;
   1214             p_closest_dist2 = dist2;
   1215         }
   1216         p_last = p_current;
   1217     }
   1218     else if (level < 10)
   1219     {
   1220         float x12 = (x1 + x2)*0.5f,       y12 = (y1 + y2)*0.5f;
   1221         float x23 = (x2 + x3)*0.5f,       y23 = (y2 + y3)*0.5f;
   1222         float x34 = (x3 + x4)*0.5f,       y34 = (y3 + y4)*0.5f;
   1223         float x123 = (x12 + x23)*0.5f,    y123 = (y12 + y23)*0.5f;
   1224         float x234 = (x23 + x34)*0.5f,    y234 = (y23 + y34)*0.5f;
   1225         float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
   1226         ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
   1227         ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
   1228     }
   1229 }
   1230 
   1231 // tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol
   1232 // Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.
   1233 ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
   1234 {
   1235     IM_ASSERT(tess_tol > 0.0f);
   1236     ImVec2 p_last = p1;
   1237     ImVec2 p_closest;
   1238     float p_closest_dist2 = FLT_MAX;
   1239     ImBezierCubicClosestPointCasteljauStep(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);
   1240     return p_closest;
   1241 }
   1242 
   1243 ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
   1244 {
   1245     ImVec2 ap = p - a;
   1246     ImVec2 ab_dir = b - a;
   1247     float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
   1248     if (dot < 0.0f)
   1249         return a;
   1250     float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
   1251     if (dot > ab_len_sqr)
   1252         return b;
   1253     return a + ab_dir * dot / ab_len_sqr;
   1254 }
   1255 
   1256 bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
   1257 {
   1258     bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
   1259     bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
   1260     bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
   1261     return ((b1 == b2) && (b2 == b3));
   1262 }
   1263 
   1264 void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
   1265 {
   1266     ImVec2 v0 = b - a;
   1267     ImVec2 v1 = c - a;
   1268     ImVec2 v2 = p - a;
   1269     const float denom = v0.x * v1.y - v1.x * v0.y;
   1270     out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
   1271     out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
   1272     out_u = 1.0f - out_v - out_w;
   1273 }
   1274 
   1275 ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
   1276 {
   1277     ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
   1278     ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
   1279     ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
   1280     float dist2_ab = ImLengthSqr(p - proj_ab);
   1281     float dist2_bc = ImLengthSqr(p - proj_bc);
   1282     float dist2_ca = ImLengthSqr(p - proj_ca);
   1283     float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
   1284     if (m == dist2_ab)
   1285         return proj_ab;
   1286     if (m == dist2_bc)
   1287         return proj_bc;
   1288     return proj_ca;
   1289 }
   1290 
   1291 //-----------------------------------------------------------------------------
   1292 // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
   1293 //-----------------------------------------------------------------------------
   1294 
   1295 // Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
   1296 int ImStricmp(const char* str1, const char* str2)
   1297 {
   1298     int d;
   1299     while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
   1300     return d;
   1301 }
   1302 
   1303 int ImStrnicmp(const char* str1, const char* str2, size_t count)
   1304 {
   1305     int d = 0;
   1306     while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
   1307     return d;
   1308 }
   1309 
   1310 void ImStrncpy(char* dst, const char* src, size_t count)
   1311 {
   1312     if (count < 1)
   1313         return;
   1314     if (count > 1)
   1315         strncpy(dst, src, count - 1);
   1316     dst[count - 1] = 0;
   1317 }
   1318 
   1319 char* ImStrdup(const char* str)
   1320 {
   1321     size_t len = strlen(str);
   1322     void* buf = IM_ALLOC(len + 1);
   1323     return (char*)memcpy(buf, (const void*)str, len + 1);
   1324 }
   1325 
   1326 char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
   1327 {
   1328     size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
   1329     size_t src_size = strlen(src) + 1;
   1330     if (dst_buf_size < src_size)
   1331     {
   1332         IM_FREE(dst);
   1333         dst = (char*)IM_ALLOC(src_size);
   1334         if (p_dst_size)
   1335             *p_dst_size = src_size;
   1336     }
   1337     return (char*)memcpy(dst, (const void*)src, src_size);
   1338 }
   1339 
   1340 const char* ImStrchrRange(const char* str, const char* str_end, char c)
   1341 {
   1342     const char* p = (const char*)memchr(str, (int)c, str_end - str);
   1343     return p;
   1344 }
   1345 
   1346 int ImStrlenW(const ImWchar* str)
   1347 {
   1348     //return (int)wcslen((const wchar_t*)str);  // FIXME-OPT: Could use this when wchar_t are 16-bit
   1349     int n = 0;
   1350     while (*str++) n++;
   1351     return n;
   1352 }
   1353 
   1354 // Find end-of-line. Return pointer will point to either first \n, either str_end.
   1355 const char* ImStreolRange(const char* str, const char* str_end)
   1356 {
   1357     const char* p = (const char*)memchr(str, '\n', str_end - str);
   1358     return p ? p : str_end;
   1359 }
   1360 
   1361 const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
   1362 {
   1363     while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
   1364         buf_mid_line--;
   1365     return buf_mid_line;
   1366 }
   1367 
   1368 const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
   1369 {
   1370     if (!needle_end)
   1371         needle_end = needle + strlen(needle);
   1372 
   1373     const char un0 = (char)toupper(*needle);
   1374     while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
   1375     {
   1376         if (toupper(*haystack) == un0)
   1377         {
   1378             const char* b = needle + 1;
   1379             for (const char* a = haystack + 1; b < needle_end; a++, b++)
   1380                 if (toupper(*a) != toupper(*b))
   1381                     break;
   1382             if (b == needle_end)
   1383                 return haystack;
   1384         }
   1385         haystack++;
   1386     }
   1387     return NULL;
   1388 }
   1389 
   1390 // 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.
   1391 void ImStrTrimBlanks(char* buf)
   1392 {
   1393     char* p = buf;
   1394     while (p[0] == ' ' || p[0] == '\t')     // Leading blanks
   1395         p++;
   1396     char* p_start = p;
   1397     while (*p != 0)                         // Find end of string
   1398         p++;
   1399     while (p > p_start && (p[-1] == ' ' || p[-1] == '\t'))  // Trailing blanks
   1400         p--;
   1401     if (p_start != buf)                     // Copy memory if we had leading blanks
   1402         memmove(buf, p_start, p - p_start);
   1403     buf[p - p_start] = 0;                   // Zero terminate
   1404 }
   1405 
   1406 const char* ImStrSkipBlank(const char* str)
   1407 {
   1408     while (str[0] == ' ' || str[0] == '\t')
   1409         str++;
   1410     return str;
   1411 }
   1412 
   1413 // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
   1414 // 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.
   1415 // B) When buf==NULL vsnprintf() will return the output size.
   1416 #ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
   1417 
   1418 // We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)
   1419 // You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
   1420 // and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are
   1421 // designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
   1422 #ifdef IMGUI_USE_STB_SPRINTF
   1423 #define STB_SPRINTF_IMPLEMENTATION
   1424 #include "stb_sprintf.h"
   1425 #endif
   1426 
   1427 #if defined(_MSC_VER) && !defined(vsnprintf)
   1428 #define vsnprintf _vsnprintf
   1429 #endif
   1430 
   1431 int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
   1432 {
   1433     va_list args;
   1434     va_start(args, fmt);
   1435 #ifdef IMGUI_USE_STB_SPRINTF
   1436     int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
   1437 #else
   1438     int w = vsnprintf(buf, buf_size, fmt, args);
   1439 #endif
   1440     va_end(args);
   1441     if (buf == NULL)
   1442         return w;
   1443     if (w == -1 || w >= (int)buf_size)
   1444         w = (int)buf_size - 1;
   1445     buf[w] = 0;
   1446     return w;
   1447 }
   1448 
   1449 int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
   1450 {
   1451 #ifdef IMGUI_USE_STB_SPRINTF
   1452     int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
   1453 #else
   1454     int w = vsnprintf(buf, buf_size, fmt, args);
   1455 #endif
   1456     if (buf == NULL)
   1457         return w;
   1458     if (w == -1 || w >= (int)buf_size)
   1459         w = (int)buf_size - 1;
   1460     buf[w] = 0;
   1461     return w;
   1462 }
   1463 #endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
   1464 
   1465 // CRC32 needs a 1KB lookup table (not cache friendly)
   1466 // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
   1467 // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
   1468 static const ImU32 GCrc32LookupTable[256] =
   1469 {
   1470     0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
   1471     0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
   1472     0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
   1473     0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
   1474     0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
   1475     0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
   1476     0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
   1477     0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
   1478     0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
   1479     0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
   1480     0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
   1481     0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
   1482     0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
   1483     0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
   1484     0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
   1485     0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
   1486 };
   1487 
   1488 // Known size hash
   1489 // It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
   1490 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
   1491 ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed)
   1492 {
   1493     ImU32 crc = ~seed;
   1494     const unsigned char* data = (const unsigned char*)data_p;
   1495     const ImU32* crc32_lut = GCrc32LookupTable;
   1496     while (data_size-- != 0)
   1497         crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
   1498     return ~crc;
   1499 }
   1500 
   1501 // Zero-terminated string hash, with support for ### to reset back to seed value
   1502 // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
   1503 // Because this syntax is rarely used we are optimizing for the common case.
   1504 // - If we reach ### in the string we discard the hash so far and reset to the seed.
   1505 // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
   1506 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
   1507 ImGuiID ImHashStr(const char* data_p, size_t data_size, ImU32 seed)
   1508 {
   1509     seed = ~seed;
   1510     ImU32 crc = seed;
   1511     const unsigned char* data = (const unsigned char*)data_p;
   1512     const ImU32* crc32_lut = GCrc32LookupTable;
   1513     if (data_size != 0)
   1514     {
   1515         while (data_size-- != 0)
   1516         {
   1517             unsigned char c = *data++;
   1518             if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
   1519                 crc = seed;
   1520             crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
   1521         }
   1522     }
   1523     else
   1524     {
   1525         while (unsigned char c = *data++)
   1526         {
   1527             if (c == '#' && data[0] == '#' && data[1] == '#')
   1528                 crc = seed;
   1529             crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
   1530         }
   1531     }
   1532     return ~crc;
   1533 }
   1534 
   1535 //-----------------------------------------------------------------------------
   1536 // [SECTION] MISC HELPERS/UTILITIES (File functions)
   1537 //-----------------------------------------------------------------------------
   1538 
   1539 // Default file functions
   1540 #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
   1541 
   1542 ImFileHandle ImFileOpen(const char* filename, const char* mode)
   1543 {
   1544 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
   1545     // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
   1546     // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
   1547     const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
   1548     const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
   1549     ImVector<ImWchar> buf;
   1550     buf.resize(filename_wsize + mode_wsize);
   1551     ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
   1552     ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
   1553     return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]);
   1554 #else
   1555     return fopen(filename, mode);
   1556 #endif
   1557 }
   1558 
   1559 // 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.
   1560 bool    ImFileClose(ImFileHandle f)     { return fclose(f) == 0; }
   1561 ImU64   ImFileGetSize(ImFileHandle f)   { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; }
   1562 ImU64   ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f)           { return fread(data, (size_t)sz, (size_t)count, f); }
   1563 ImU64   ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f)    { return fwrite(data, (size_t)sz, (size_t)count, f); }
   1564 #endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
   1565 
   1566 // Helper: Load file content into memory
   1567 // Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
   1568 // This can't really be used with "rt" because fseek size won't match read size.
   1569 void*   ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
   1570 {
   1571     IM_ASSERT(filename && mode);
   1572     if (out_file_size)
   1573         *out_file_size = 0;
   1574 
   1575     ImFileHandle f;
   1576     if ((f = ImFileOpen(filename, mode)) == NULL)
   1577         return NULL;
   1578 
   1579     size_t file_size = (size_t)ImFileGetSize(f);
   1580     if (file_size == (size_t)-1)
   1581     {
   1582         ImFileClose(f);
   1583         return NULL;
   1584     }
   1585 
   1586     void* file_data = IM_ALLOC(file_size + padding_bytes);
   1587     if (file_data == NULL)
   1588     {
   1589         ImFileClose(f);
   1590         return NULL;
   1591     }
   1592     if (ImFileRead(file_data, 1, file_size, f) != file_size)
   1593     {
   1594         ImFileClose(f);
   1595         IM_FREE(file_data);
   1596         return NULL;
   1597     }
   1598     if (padding_bytes > 0)
   1599         memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
   1600 
   1601     ImFileClose(f);
   1602     if (out_file_size)
   1603         *out_file_size = file_size;
   1604 
   1605     return file_data;
   1606 }
   1607 
   1608 //-----------------------------------------------------------------------------
   1609 // [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
   1610 //-----------------------------------------------------------------------------
   1611 
   1612 // Convert UTF-8 to 32-bit character, process single character input.
   1613 // A nearly-branchless UTF-8 decoder, based on work of Christopher Wellons (https://github.com/skeeto/branchless-utf8).
   1614 // We handle UTF-8 decoding error by skipping forward.
   1615 int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
   1616 {
   1617     static const char lengths[32] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0 };
   1618     static const int masks[]  = { 0x00, 0x7f, 0x1f, 0x0f, 0x07 };
   1619     static const uint32_t mins[] = { 0x400000, 0, 0x80, 0x800, 0x10000 };
   1620     static const int shiftc[] = { 0, 18, 12, 6, 0 };
   1621     static const int shifte[] = { 0, 6, 4, 2, 0 };
   1622     int len = lengths[*(const unsigned char*)in_text >> 3];
   1623     int wanted = len + !len;
   1624 
   1625     if (in_text_end == NULL)
   1626         in_text_end = in_text + wanted; // Max length, nulls will be taken into account.
   1627 
   1628     // Copy at most 'len' bytes, stop copying at 0 or past in_text_end. Branch predictor does a good job here,
   1629     // so it is fast even with excessive branching.
   1630     unsigned char s[4];
   1631     s[0] = in_text + 0 < in_text_end ? in_text[0] : 0;
   1632     s[1] = in_text + 1 < in_text_end ? in_text[1] : 0;
   1633     s[2] = in_text + 2 < in_text_end ? in_text[2] : 0;
   1634     s[3] = in_text + 3 < in_text_end ? in_text[3] : 0;
   1635 
   1636     // Assume a four-byte character and load four bytes. Unused bits are shifted out.
   1637     *out_char  = (uint32_t)(s[0] & masks[len]) << 18;
   1638     *out_char |= (uint32_t)(s[1] & 0x3f) << 12;
   1639     *out_char |= (uint32_t)(s[2] & 0x3f) <<  6;
   1640     *out_char |= (uint32_t)(s[3] & 0x3f) <<  0;
   1641     *out_char >>= shiftc[len];
   1642 
   1643     // Accumulate the various error conditions.
   1644     int e = 0;
   1645     e  = (*out_char < mins[len]) << 6; // non-canonical encoding
   1646     e |= ((*out_char >> 11) == 0x1b) << 7;  // surrogate half?
   1647     e |= (*out_char > IM_UNICODE_CODEPOINT_MAX) << 8;  // out of range?
   1648     e |= (s[1] & 0xc0) >> 2;
   1649     e |= (s[2] & 0xc0) >> 4;
   1650     e |= (s[3]       ) >> 6;
   1651     e ^= 0x2a; // top two bits of each tail byte correct?
   1652     e >>= shifte[len];
   1653 
   1654     if (e)
   1655     {
   1656         // No bytes are consumed when *in_text == 0 || in_text == in_text_end.
   1657         // One byte is consumed in case of invalid first byte of in_text.
   1658         // All available bytes (at most `len` bytes) are consumed on incomplete/invalid second to last bytes.
   1659         // Invalid or incomplete input may consume less bytes than wanted, therefore every byte has to be inspected in s.
   1660         wanted = ImMin(wanted, !!s[0] + !!s[1] + !!s[2] + !!s[3]);
   1661         *out_char = IM_UNICODE_CODEPOINT_INVALID;
   1662     }
   1663 
   1664     return wanted;
   1665 }
   1666 
   1667 int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
   1668 {
   1669     ImWchar* buf_out = buf;
   1670     ImWchar* buf_end = buf + buf_size;
   1671     while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
   1672     {
   1673         unsigned int c;
   1674         in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
   1675         if (c == 0)
   1676             break;
   1677         *buf_out++ = (ImWchar)c;
   1678     }
   1679     *buf_out = 0;
   1680     if (in_text_remaining)
   1681         *in_text_remaining = in_text;
   1682     return (int)(buf_out - buf);
   1683 }
   1684 
   1685 int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
   1686 {
   1687     int char_count = 0;
   1688     while ((!in_text_end || in_text < in_text_end) && *in_text)
   1689     {
   1690         unsigned int c;
   1691         in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
   1692         if (c == 0)
   1693             break;
   1694         char_count++;
   1695     }
   1696     return char_count;
   1697 }
   1698 
   1699 // Based on stb_to_utf8() from github.com/nothings/stb/
   1700 static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
   1701 {
   1702     if (c < 0x80)
   1703     {
   1704         buf[0] = (char)c;
   1705         return 1;
   1706     }
   1707     if (c < 0x800)
   1708     {
   1709         if (buf_size < 2) return 0;
   1710         buf[0] = (char)(0xc0 + (c >> 6));
   1711         buf[1] = (char)(0x80 + (c & 0x3f));
   1712         return 2;
   1713     }
   1714     if (c < 0x10000)
   1715     {
   1716         if (buf_size < 3) return 0;
   1717         buf[0] = (char)(0xe0 + (c >> 12));
   1718         buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
   1719         buf[2] = (char)(0x80 + ((c ) & 0x3f));
   1720         return 3;
   1721     }
   1722     if (c <= 0x10FFFF)
   1723     {
   1724         if (buf_size < 4) return 0;
   1725         buf[0] = (char)(0xf0 + (c >> 18));
   1726         buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
   1727         buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
   1728         buf[3] = (char)(0x80 + ((c ) & 0x3f));
   1729         return 4;
   1730     }
   1731     // Invalid code point, the max unicode is 0x10FFFF
   1732     return 0;
   1733 }
   1734 
   1735 // Not optimal but we very rarely use this function.
   1736 int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
   1737 {
   1738     unsigned int unused = 0;
   1739     return ImTextCharFromUtf8(&unused, in_text, in_text_end);
   1740 }
   1741 
   1742 static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
   1743 {
   1744     if (c < 0x80) return 1;
   1745     if (c < 0x800) return 2;
   1746     if (c < 0x10000) return 3;
   1747     if (c <= 0x10FFFF) return 4;
   1748     return 3;
   1749 }
   1750 
   1751 int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
   1752 {
   1753     char* buf_out = buf;
   1754     const char* buf_end = buf + buf_size;
   1755     while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
   1756     {
   1757         unsigned int c = (unsigned int)(*in_text++);
   1758         if (c < 0x80)
   1759             *buf_out++ = (char)c;
   1760         else
   1761             buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);
   1762     }
   1763     *buf_out = 0;
   1764     return (int)(buf_out - buf);
   1765 }
   1766 
   1767 int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
   1768 {
   1769     int bytes_count = 0;
   1770     while ((!in_text_end || in_text < in_text_end) && *in_text)
   1771     {
   1772         unsigned int c = (unsigned int)(*in_text++);
   1773         if (c < 0x80)
   1774             bytes_count++;
   1775         else
   1776             bytes_count += ImTextCountUtf8BytesFromChar(c);
   1777     }
   1778     return bytes_count;
   1779 }
   1780 
   1781 //-----------------------------------------------------------------------------
   1782 // [SECTION] MISC HELPERS/UTILITIES (Color functions)
   1783 // Note: The Convert functions are early design which are not consistent with other API.
   1784 //-----------------------------------------------------------------------------
   1785 
   1786 IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)
   1787 {
   1788     float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
   1789     int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
   1790     int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
   1791     int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
   1792     return IM_COL32(r, g, b, 0xFF);
   1793 }
   1794 
   1795 ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
   1796 {
   1797     float s = 1.0f / 255.0f;
   1798     return ImVec4(
   1799         ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
   1800         ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
   1801         ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
   1802         ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
   1803 }
   1804 
   1805 ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
   1806 {
   1807     ImU32 out;
   1808     out  = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
   1809     out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
   1810     out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
   1811     out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
   1812     return out;
   1813 }
   1814 
   1815 // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
   1816 // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
   1817 void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
   1818 {
   1819     float K = 0.f;
   1820     if (g < b)
   1821     {
   1822         ImSwap(g, b);
   1823         K = -1.f;
   1824     }
   1825     if (r < g)
   1826     {
   1827         ImSwap(r, g);
   1828         K = -2.f / 6.f - K;
   1829     }
   1830 
   1831     const float chroma = r - (g < b ? g : b);
   1832     out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
   1833     out_s = chroma / (r + 1e-20f);
   1834     out_v = r;
   1835 }
   1836 
   1837 // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
   1838 // also http://en.wikipedia.org/wiki/HSL_and_HSV
   1839 void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
   1840 {
   1841     if (s == 0.0f)
   1842     {
   1843         // gray
   1844         out_r = out_g = out_b = v;
   1845         return;
   1846     }
   1847 
   1848     h = ImFmod(h, 1.0f) / (60.0f / 360.0f);
   1849     int   i = (int)h;
   1850     float f = h - (float)i;
   1851     float p = v * (1.0f - s);
   1852     float q = v * (1.0f - s * f);
   1853     float t = v * (1.0f - s * (1.0f - f));
   1854 
   1855     switch (i)
   1856     {
   1857     case 0: out_r = v; out_g = t; out_b = p; break;
   1858     case 1: out_r = q; out_g = v; out_b = p; break;
   1859     case 2: out_r = p; out_g = v; out_b = t; break;
   1860     case 3: out_r = p; out_g = q; out_b = v; break;
   1861     case 4: out_r = t; out_g = p; out_b = v; break;
   1862     case 5: default: out_r = v; out_g = p; out_b = q; break;
   1863     }
   1864 }
   1865 
   1866 //-----------------------------------------------------------------------------
   1867 // [SECTION] ImGuiStorage
   1868 // Helper: Key->value storage
   1869 //-----------------------------------------------------------------------------
   1870 
   1871 // std::lower_bound but without the bullshit
   1872 static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)
   1873 {
   1874     ImGuiStorage::ImGuiStoragePair* first = data.Data;
   1875     ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
   1876     size_t count = (size_t)(last - first);
   1877     while (count > 0)
   1878     {
   1879         size_t count2 = count >> 1;
   1880         ImGuiStorage::ImGuiStoragePair* mid = first + count2;
   1881         if (mid->key < key)
   1882         {
   1883             first = ++mid;
   1884             count -= count2 + 1;
   1885         }
   1886         else
   1887         {
   1888             count = count2;
   1889         }
   1890     }
   1891     return first;
   1892 }
   1893 
   1894 // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
   1895 void ImGuiStorage::BuildSortByKey()
   1896 {
   1897     struct StaticFunc
   1898     {
   1899         static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
   1900         {
   1901             // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
   1902             if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
   1903             if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
   1904             return 0;
   1905         }
   1906     };
   1907     if (Data.Size > 1)
   1908         ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID);
   1909 }
   1910 
   1911 int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
   1912 {
   1913     ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
   1914     if (it == Data.end() || it->key != key)
   1915         return default_val;
   1916     return it->val_i;
   1917 }
   1918 
   1919 bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
   1920 {
   1921     return GetInt(key, default_val ? 1 : 0) != 0;
   1922 }
   1923 
   1924 float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
   1925 {
   1926     ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
   1927     if (it == Data.end() || it->key != key)
   1928         return default_val;
   1929     return it->val_f;
   1930 }
   1931 
   1932 void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
   1933 {
   1934     ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
   1935     if (it == Data.end() || it->key != key)
   1936         return NULL;
   1937     return it->val_p;
   1938 }
   1939 
   1940 // 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.
   1941 int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
   1942 {
   1943     ImGuiStoragePair* it = LowerBound(Data, key);
   1944     if (it == Data.end() || it->key != key)
   1945         it = Data.insert(it, ImGuiStoragePair(key, default_val));
   1946     return &it->val_i;
   1947 }
   1948 
   1949 bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
   1950 {
   1951     return (bool*)GetIntRef(key, default_val ? 1 : 0);
   1952 }
   1953 
   1954 float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
   1955 {
   1956     ImGuiStoragePair* it = LowerBound(Data, key);
   1957     if (it == Data.end() || it->key != key)
   1958         it = Data.insert(it, ImGuiStoragePair(key, default_val));
   1959     return &it->val_f;
   1960 }
   1961 
   1962 void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
   1963 {
   1964     ImGuiStoragePair* it = LowerBound(Data, key);
   1965     if (it == Data.end() || it->key != key)
   1966         it = Data.insert(it, ImGuiStoragePair(key, default_val));
   1967     return &it->val_p;
   1968 }
   1969 
   1970 // 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)
   1971 void ImGuiStorage::SetInt(ImGuiID key, int val)
   1972 {
   1973     ImGuiStoragePair* it = LowerBound(Data, key);
   1974     if (it == Data.end() || it->key != key)
   1975     {
   1976         Data.insert(it, ImGuiStoragePair(key, val));
   1977         return;
   1978     }
   1979     it->val_i = val;
   1980 }
   1981 
   1982 void ImGuiStorage::SetBool(ImGuiID key, bool val)
   1983 {
   1984     SetInt(key, val ? 1 : 0);
   1985 }
   1986 
   1987 void ImGuiStorage::SetFloat(ImGuiID key, float val)
   1988 {
   1989     ImGuiStoragePair* it = LowerBound(Data, key);
   1990     if (it == Data.end() || it->key != key)
   1991     {
   1992         Data.insert(it, ImGuiStoragePair(key, val));
   1993         return;
   1994     }
   1995     it->val_f = val;
   1996 }
   1997 
   1998 void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
   1999 {
   2000     ImGuiStoragePair* it = LowerBound(Data, key);
   2001     if (it == Data.end() || it->key != key)
   2002     {
   2003         Data.insert(it, ImGuiStoragePair(key, val));
   2004         return;
   2005     }
   2006     it->val_p = val;
   2007 }
   2008 
   2009 void ImGuiStorage::SetAllInt(int v)
   2010 {
   2011     for (int i = 0; i < Data.Size; i++)
   2012         Data[i].val_i = v;
   2013 }
   2014 
   2015 //-----------------------------------------------------------------------------
   2016 // [SECTION] ImGuiTextFilter
   2017 //-----------------------------------------------------------------------------
   2018 
   2019 // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
   2020 ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
   2021 {
   2022     if (default_filter)
   2023     {
   2024         ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
   2025         Build();
   2026     }
   2027     else
   2028     {
   2029         InputBuf[0] = 0;
   2030         CountGrep = 0;
   2031     }
   2032 }
   2033 
   2034 bool ImGuiTextFilter::Draw(const char* label, float width)
   2035 {
   2036     if (width != 0.0f)
   2037         ImGui::SetNextItemWidth(width);
   2038     bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
   2039     if (value_changed)
   2040         Build();
   2041     return value_changed;
   2042 }
   2043 
   2044 void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
   2045 {
   2046     out->resize(0);
   2047     const char* wb = b;
   2048     const char* we = wb;
   2049     while (we < e)
   2050     {
   2051         if (*we == separator)
   2052         {
   2053             out->push_back(ImGuiTextRange(wb, we));
   2054             wb = we + 1;
   2055         }
   2056         we++;
   2057     }
   2058     if (wb != we)
   2059         out->push_back(ImGuiTextRange(wb, we));
   2060 }
   2061 
   2062 void ImGuiTextFilter::Build()
   2063 {
   2064     Filters.resize(0);
   2065     ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf));
   2066     input_range.split(',', &Filters);
   2067 
   2068     CountGrep = 0;
   2069     for (int i = 0; i != Filters.Size; i++)
   2070     {
   2071         ImGuiTextRange& f = Filters[i];
   2072         while (f.b < f.e && ImCharIsBlankA(f.b[0]))
   2073             f.b++;
   2074         while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
   2075             f.e--;
   2076         if (f.empty())
   2077             continue;
   2078         if (Filters[i].b[0] != '-')
   2079             CountGrep += 1;
   2080     }
   2081 }
   2082 
   2083 bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
   2084 {
   2085     if (Filters.empty())
   2086         return true;
   2087 
   2088     if (text == NULL)
   2089         text = "";
   2090 
   2091     for (int i = 0; i != Filters.Size; i++)
   2092     {
   2093         const ImGuiTextRange& f = Filters[i];
   2094         if (f.empty())
   2095             continue;
   2096         if (f.b[0] == '-')
   2097         {
   2098             // Subtract
   2099             if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
   2100                 return false;
   2101         }
   2102         else
   2103         {
   2104             // Grep
   2105             if (ImStristr(text, text_end, f.b, f.e) != NULL)
   2106                 return true;
   2107         }
   2108     }
   2109 
   2110     // Implicit * grep
   2111     if (CountGrep == 0)
   2112         return true;
   2113 
   2114     return false;
   2115 }
   2116 
   2117 //-----------------------------------------------------------------------------
   2118 // [SECTION] ImGuiTextBuffer
   2119 //-----------------------------------------------------------------------------
   2120 
   2121 // On some platform vsnprintf() takes va_list by reference and modifies it.
   2122 // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
   2123 #ifndef va_copy
   2124 #if defined(__GNUC__) || defined(__clang__)
   2125 #define va_copy(dest, src) __builtin_va_copy(dest, src)
   2126 #else
   2127 #define va_copy(dest, src) (dest = src)
   2128 #endif
   2129 #endif
   2130 
   2131 char ImGuiTextBuffer::EmptyString[1] = { 0 };
   2132 
   2133 void ImGuiTextBuffer::append(const char* str, const char* str_end)
   2134 {
   2135     int len = str_end ? (int)(str_end - str) : (int)strlen(str);
   2136 
   2137     // Add zero-terminator the first time
   2138     const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
   2139     const int needed_sz = write_off + len;
   2140     if (write_off + len >= Buf.Capacity)
   2141     {
   2142         int new_capacity = Buf.Capacity * 2;
   2143         Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
   2144     }
   2145 
   2146     Buf.resize(needed_sz);
   2147     memcpy(&Buf[write_off - 1], str, (size_t)len);
   2148     Buf[write_off - 1 + len] = 0;
   2149 }
   2150 
   2151 void ImGuiTextBuffer::appendf(const char* fmt, ...)
   2152 {
   2153     va_list args;
   2154     va_start(args, fmt);
   2155     appendfv(fmt, args);
   2156     va_end(args);
   2157 }
   2158 
   2159 // Helper: Text buffer for logging/accumulating text
   2160 void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
   2161 {
   2162     va_list args_copy;
   2163     va_copy(args_copy, args);
   2164 
   2165     int len = ImFormatStringV(NULL, 0, fmt, args);         // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
   2166     if (len <= 0)
   2167     {
   2168         va_end(args_copy);
   2169         return;
   2170     }
   2171 
   2172     // Add zero-terminator the first time
   2173     const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
   2174     const int needed_sz = write_off + len;
   2175     if (write_off + len >= Buf.Capacity)
   2176     {
   2177         int new_capacity = Buf.Capacity * 2;
   2178         Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
   2179     }
   2180 
   2181     Buf.resize(needed_sz);
   2182     ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
   2183     va_end(args_copy);
   2184 }
   2185 
   2186 //-----------------------------------------------------------------------------
   2187 // [SECTION] ImGuiListClipper
   2188 // This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed
   2189 // the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO)
   2190 //-----------------------------------------------------------------------------
   2191 
   2192 // FIXME-TABLE: This prevents us from using ImGuiListClipper _inside_ a table cell.
   2193 // The problem we have is that without a Begin/End scheme for rows using the clipper is ambiguous.
   2194 static bool GetSkipItemForListClipping()
   2195 {
   2196     ImGuiContext& g = *GImGui;
   2197     return (g.CurrentTable ? g.CurrentTable->HostSkipItems : g.CurrentWindow->SkipItems);
   2198 }
   2199 
   2200 // Helper to calculate coarse clipping of large list of evenly sized items.
   2201 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
   2202 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
   2203 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
   2204 {
   2205     ImGuiContext& g = *GImGui;
   2206     ImGuiWindow* window = g.CurrentWindow;
   2207     if (g.LogEnabled)
   2208     {
   2209         // If logging is active, do not perform any clipping
   2210         *out_items_display_start = 0;
   2211         *out_items_display_end = items_count;
   2212         return;
   2213     }
   2214     if (GetSkipItemForListClipping())
   2215     {
   2216         *out_items_display_start = *out_items_display_end = 0;
   2217         return;
   2218     }
   2219 
   2220     // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
   2221     ImRect unclipped_rect = window->ClipRect;
   2222     if (g.NavMoveRequest)
   2223         unclipped_rect.Add(g.NavScoringRect);
   2224     if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
   2225         unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max));
   2226 
   2227     const ImVec2 pos = window->DC.CursorPos;
   2228     int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
   2229     int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
   2230 
   2231     // When performing a navigation request, ensure we have one item extra in the direction we are moving to
   2232     if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
   2233         start--;
   2234     if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
   2235         end++;
   2236 
   2237     start = ImClamp(start, 0, items_count);
   2238     end = ImClamp(end + 1, start, items_count);
   2239     *out_items_display_start = start;
   2240     *out_items_display_end = end;
   2241 }
   2242 
   2243 static void SetCursorPosYAndSetupForPrevLine(float pos_y, float line_height)
   2244 {
   2245     // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
   2246     // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
   2247     // The clipper should probably have a 4th step to display the last item in a regular manner.
   2248     ImGuiContext& g = *GImGui;
   2249     ImGuiWindow* window = g.CurrentWindow;
   2250     float off_y = pos_y - window->DC.CursorPos.y;
   2251     window->DC.CursorPos.y = pos_y;
   2252     window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y);
   2253     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.
   2254     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.
   2255     if (ImGuiOldColumns* columns = window->DC.CurrentColumns)
   2256         columns->LineMinY = window->DC.CursorPos.y;                         // Setting this so that cell Y position are set properly
   2257     if (ImGuiTable* table = g.CurrentTable)
   2258     {
   2259         if (table->IsInsideRow)
   2260             ImGui::TableEndRow(table);
   2261         table->RowPosY2 = window->DC.CursorPos.y;
   2262         const int row_increase = (int)((off_y / line_height) + 0.5f);
   2263         //table->CurrentRow += row_increase; // Can't do without fixing TableEndRow()
   2264         table->RowBgColorCounter += row_increase;
   2265     }
   2266 }
   2267 
   2268 ImGuiListClipper::ImGuiListClipper()
   2269 {
   2270     memset(this, 0, sizeof(*this));
   2271     ItemsCount = -1;
   2272 }
   2273 
   2274 ImGuiListClipper::~ImGuiListClipper()
   2275 {
   2276     IM_ASSERT(ItemsCount == -1 && "Forgot to call End(), or to Step() until false?");
   2277 }
   2278 
   2279 // Use case A: Begin() called from constructor with items_height<0, then called again from Step() in StepNo 1
   2280 // Use case B: Begin() called from constructor with items_height>0
   2281 // 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.
   2282 void ImGuiListClipper::Begin(int items_count, float items_height)
   2283 {
   2284     ImGuiContext& g = *GImGui;
   2285     ImGuiWindow* window = g.CurrentWindow;
   2286 
   2287     if (ImGuiTable* table = g.CurrentTable)
   2288         if (table->IsInsideRow)
   2289             ImGui::TableEndRow(table);
   2290 
   2291     StartPosY = window->DC.CursorPos.y;
   2292     ItemsHeight = items_height;
   2293     ItemsCount = items_count;
   2294     ItemsFrozen = 0;
   2295     StepNo = 0;
   2296     DisplayStart = -1;
   2297     DisplayEnd = 0;
   2298 }
   2299 
   2300 void ImGuiListClipper::End()
   2301 {
   2302     if (ItemsCount < 0) // Already ended
   2303         return;
   2304 
   2305     // 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.
   2306     if (ItemsCount < INT_MAX && DisplayStart >= 0)
   2307         SetCursorPosYAndSetupForPrevLine(StartPosY + (ItemsCount - ItemsFrozen) * ItemsHeight, ItemsHeight);
   2308     ItemsCount = -1;
   2309     StepNo = 3;
   2310 }
   2311 
   2312 bool ImGuiListClipper::Step()
   2313 {
   2314     ImGuiContext& g = *GImGui;
   2315     ImGuiWindow* window = g.CurrentWindow;
   2316 
   2317     ImGuiTable* table = g.CurrentTable;
   2318     if (table && table->IsInsideRow)
   2319         ImGui::TableEndRow(table);
   2320 
   2321     // No items
   2322     if (ItemsCount == 0 || GetSkipItemForListClipping())
   2323     {
   2324         End();
   2325         return false;
   2326     }
   2327 
   2328     // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height)
   2329     if (StepNo == 0)
   2330     {
   2331         // While we are in frozen row state, keep displaying items one by one, unclipped
   2332         // FIXME: Could be stored as a table-agnostic state.
   2333         if (table != NULL && !table->IsUnfrozenRows)
   2334         {
   2335             DisplayStart = ItemsFrozen;
   2336             DisplayEnd = ItemsFrozen + 1;
   2337             ItemsFrozen++;
   2338             return true;
   2339         }
   2340 
   2341         StartPosY = window->DC.CursorPos.y;
   2342         if (ItemsHeight <= 0.0f)
   2343         {
   2344             // Submit the first item so we can measure its height (generally it is 0..1)
   2345             DisplayStart = ItemsFrozen;
   2346             DisplayEnd = ItemsFrozen + 1;
   2347             StepNo = 1;
   2348             return true;
   2349         }
   2350 
   2351         // Already has item height (given by user in Begin): skip to calculating step
   2352         DisplayStart = DisplayEnd;
   2353         StepNo = 2;
   2354     }
   2355 
   2356     // Step 1: the clipper infer height from first element
   2357     if (StepNo == 1)
   2358     {
   2359         IM_ASSERT(ItemsHeight <= 0.0f);
   2360         if (table)
   2361         {
   2362             const float pos_y1 = table->RowPosY1;   // Using this instead of StartPosY to handle clipper straddling the frozen row
   2363             const float pos_y2 = table->RowPosY2;   // Using this instead of CursorPos.y to take account of tallest cell.
   2364             ItemsHeight = pos_y2 - pos_y1;
   2365             window->DC.CursorPos.y = pos_y2;
   2366         }
   2367         else
   2368         {
   2369             ItemsHeight = window->DC.CursorPos.y - StartPosY;
   2370         }
   2371         IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
   2372         StepNo = 2;
   2373     }
   2374 
   2375     // Reached end of list
   2376     if (DisplayEnd >= ItemsCount)
   2377     {
   2378         End();
   2379         return false;
   2380     }
   2381 
   2382     // Step 2: calculate the actual range of elements to display, and position the cursor before the first element
   2383     if (StepNo == 2)
   2384     {
   2385         IM_ASSERT(ItemsHeight > 0.0f);
   2386 
   2387         int already_submitted = DisplayEnd;
   2388         ImGui::CalcListClipping(ItemsCount - already_submitted, ItemsHeight, &DisplayStart, &DisplayEnd);
   2389         DisplayStart += already_submitted;
   2390         DisplayEnd += already_submitted;
   2391 
   2392         // Seek cursor
   2393         if (DisplayStart > already_submitted)
   2394             SetCursorPosYAndSetupForPrevLine(StartPosY + (DisplayStart - ItemsFrozen) * ItemsHeight, ItemsHeight);
   2395 
   2396         StepNo = 3;
   2397         return true;
   2398     }
   2399 
   2400     // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
   2401     // Advance the cursor to the end of the list and then returns 'false' to end the loop.
   2402     if (StepNo == 3)
   2403     {
   2404         // Seek cursor
   2405         if (ItemsCount < INT_MAX)
   2406             SetCursorPosYAndSetupForPrevLine(StartPosY + (ItemsCount - ItemsFrozen) * ItemsHeight, ItemsHeight); // advance cursor
   2407         ItemsCount = -1;
   2408         return false;
   2409     }
   2410 
   2411     IM_ASSERT(0);
   2412     return false;
   2413 }
   2414 
   2415 //-----------------------------------------------------------------------------
   2416 // [SECTION] STYLING
   2417 //-----------------------------------------------------------------------------
   2418 
   2419 ImGuiStyle& ImGui::GetStyle()
   2420 {
   2421     IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
   2422     return GImGui->Style;
   2423 }
   2424 
   2425 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
   2426 {
   2427     ImGuiStyle& style = GImGui->Style;
   2428     ImVec4 c = style.Colors[idx];
   2429     c.w *= style.Alpha * alpha_mul;
   2430     return ColorConvertFloat4ToU32(c);
   2431 }
   2432 
   2433 ImU32 ImGui::GetColorU32(const ImVec4& col)
   2434 {
   2435     ImGuiStyle& style = GImGui->Style;
   2436     ImVec4 c = col;
   2437     c.w *= style.Alpha;
   2438     return ColorConvertFloat4ToU32(c);
   2439 }
   2440 
   2441 const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
   2442 {
   2443     ImGuiStyle& style = GImGui->Style;
   2444     return style.Colors[idx];
   2445 }
   2446 
   2447 ImU32 ImGui::GetColorU32(ImU32 col)
   2448 {
   2449     ImGuiStyle& style = GImGui->Style;
   2450     if (style.Alpha >= 1.0f)
   2451         return col;
   2452     ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
   2453     a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
   2454     return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
   2455 }
   2456 
   2457 // 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
   2458 void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)
   2459 {
   2460     ImGuiContext& g = *GImGui;
   2461     ImGuiColorMod backup;
   2462     backup.Col = idx;
   2463     backup.BackupValue = g.Style.Colors[idx];
   2464     g.ColorStack.push_back(backup);
   2465     g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
   2466 }
   2467 
   2468 void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
   2469 {
   2470     ImGuiContext& g = *GImGui;
   2471     ImGuiColorMod backup;
   2472     backup.Col = idx;
   2473     backup.BackupValue = g.Style.Colors[idx];
   2474     g.ColorStack.push_back(backup);
   2475     g.Style.Colors[idx] = col;
   2476 }
   2477 
   2478 void ImGui::PopStyleColor(int count)
   2479 {
   2480     ImGuiContext& g = *GImGui;
   2481     while (count > 0)
   2482     {
   2483         ImGuiColorMod& backup = g.ColorStack.back();
   2484         g.Style.Colors[backup.Col] = backup.BackupValue;
   2485         g.ColorStack.pop_back();
   2486         count--;
   2487     }
   2488 }
   2489 
   2490 struct ImGuiStyleVarInfo
   2491 {
   2492     ImGuiDataType   Type;
   2493     ImU32           Count;
   2494     ImU32           Offset;
   2495     void*           GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
   2496 };
   2497 
   2498 static const ImGuiStyleVarInfo GStyleVarInfo[] =
   2499 {
   2500     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) },               // ImGuiStyleVar_Alpha
   2501     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) },       // ImGuiStyleVar_WindowPadding
   2502     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) },      // ImGuiStyleVar_WindowRounding
   2503     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) },    // ImGuiStyleVar_WindowBorderSize
   2504     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) },       // ImGuiStyleVar_WindowMinSize
   2505     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) },    // ImGuiStyleVar_WindowTitleAlign
   2506     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) },       // ImGuiStyleVar_ChildRounding
   2507     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) },     // ImGuiStyleVar_ChildBorderSize
   2508     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) },       // ImGuiStyleVar_PopupRounding
   2509     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) },     // ImGuiStyleVar_PopupBorderSize
   2510     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) },        // ImGuiStyleVar_FramePadding
   2511     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) },       // ImGuiStyleVar_FrameRounding
   2512     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) },     // ImGuiStyleVar_FrameBorderSize
   2513     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) },         // ImGuiStyleVar_ItemSpacing
   2514     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) },    // ImGuiStyleVar_ItemInnerSpacing
   2515     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },       // ImGuiStyleVar_IndentSpacing
   2516     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, CellPadding) },         // ImGuiStyleVar_CellPadding
   2517     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) },       // ImGuiStyleVar_ScrollbarSize
   2518     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) },   // ImGuiStyleVar_ScrollbarRounding
   2519     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },         // ImGuiStyleVar_GrabMinSize
   2520     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) },        // ImGuiStyleVar_GrabRounding
   2521     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) },         // ImGuiStyleVar_TabRounding
   2522     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },     // ImGuiStyleVar_ButtonTextAlign
   2523     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
   2524 };
   2525 
   2526 static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
   2527 {
   2528     IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
   2529     IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
   2530     return &GStyleVarInfo[idx];
   2531 }
   2532 
   2533 void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
   2534 {
   2535     const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
   2536     if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
   2537     {
   2538         ImGuiContext& g = *GImGui;
   2539         float* pvar = (float*)var_info->GetVarPtr(&g.Style);
   2540         g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
   2541         *pvar = val;
   2542         return;
   2543     }
   2544     IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");
   2545 }
   2546 
   2547 void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
   2548 {
   2549     const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
   2550     if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
   2551     {
   2552         ImGuiContext& g = *GImGui;
   2553         ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
   2554         g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
   2555         *pvar = val;
   2556         return;
   2557     }
   2558     IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");
   2559 }
   2560 
   2561 void ImGui::PopStyleVar(int count)
   2562 {
   2563     ImGuiContext& g = *GImGui;
   2564     while (count > 0)
   2565     {
   2566         // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
   2567         ImGuiStyleMod& backup = g.StyleVarStack.back();
   2568         const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
   2569         void* data = info->GetVarPtr(&g.Style);
   2570         if (info->Type == ImGuiDataType_Float && info->Count == 1)      { ((float*)data)[0] = backup.BackupFloat[0]; }
   2571         else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
   2572         g.StyleVarStack.pop_back();
   2573         count--;
   2574     }
   2575 }
   2576 
   2577 const char* ImGui::GetStyleColorName(ImGuiCol idx)
   2578 {
   2579     // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
   2580     switch (idx)
   2581     {
   2582     case ImGuiCol_Text: return "Text";
   2583     case ImGuiCol_TextDisabled: return "TextDisabled";
   2584     case ImGuiCol_WindowBg: return "WindowBg";
   2585     case ImGuiCol_ChildBg: return "ChildBg";
   2586     case ImGuiCol_PopupBg: return "PopupBg";
   2587     case ImGuiCol_Border: return "Border";
   2588     case ImGuiCol_BorderShadow: return "BorderShadow";
   2589     case ImGuiCol_FrameBg: return "FrameBg";
   2590     case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
   2591     case ImGuiCol_FrameBgActive: return "FrameBgActive";
   2592     case ImGuiCol_TitleBg: return "TitleBg";
   2593     case ImGuiCol_TitleBgActive: return "TitleBgActive";
   2594     case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
   2595     case ImGuiCol_MenuBarBg: return "MenuBarBg";
   2596     case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
   2597     case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
   2598     case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
   2599     case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
   2600     case ImGuiCol_CheckMark: return "CheckMark";
   2601     case ImGuiCol_SliderGrab: return "SliderGrab";
   2602     case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
   2603     case ImGuiCol_Button: return "Button";
   2604     case ImGuiCol_ButtonHovered: return "ButtonHovered";
   2605     case ImGuiCol_ButtonActive: return "ButtonActive";
   2606     case ImGuiCol_Header: return "Header";
   2607     case ImGuiCol_HeaderHovered: return "HeaderHovered";
   2608     case ImGuiCol_HeaderActive: return "HeaderActive";
   2609     case ImGuiCol_Separator: return "Separator";
   2610     case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
   2611     case ImGuiCol_SeparatorActive: return "SeparatorActive";
   2612     case ImGuiCol_ResizeGrip: return "ResizeGrip";
   2613     case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
   2614     case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
   2615     case ImGuiCol_Tab: return "Tab";
   2616     case ImGuiCol_TabHovered: return "TabHovered";
   2617     case ImGuiCol_TabActive: return "TabActive";
   2618     case ImGuiCol_TabUnfocused: return "TabUnfocused";
   2619     case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
   2620     case ImGuiCol_PlotLines: return "PlotLines";
   2621     case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
   2622     case ImGuiCol_PlotHistogram: return "PlotHistogram";
   2623     case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
   2624     case ImGuiCol_TableHeaderBg: return "TableHeaderBg";
   2625     case ImGuiCol_TableBorderStrong: return "TableBorderStrong";
   2626     case ImGuiCol_TableBorderLight: return "TableBorderLight";
   2627     case ImGuiCol_TableRowBg: return "TableRowBg";
   2628     case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt";
   2629     case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
   2630     case ImGuiCol_DragDropTarget: return "DragDropTarget";
   2631     case ImGuiCol_NavHighlight: return "NavHighlight";
   2632     case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
   2633     case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
   2634     case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
   2635     }
   2636     IM_ASSERT(0);
   2637     return "Unknown";
   2638 }
   2639 
   2640 
   2641 //-----------------------------------------------------------------------------
   2642 // [SECTION] RENDER HELPERS
   2643 // Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change,
   2644 // we need a nicer separation between low-level functions and high-level functions relying on the ImGui context.
   2645 // Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context.
   2646 //-----------------------------------------------------------------------------
   2647 
   2648 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
   2649 {
   2650     const char* text_display_end = text;
   2651     if (!text_end)
   2652         text_end = (const char*)-1;
   2653 
   2654     while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
   2655         text_display_end++;
   2656     return text_display_end;
   2657 }
   2658 
   2659 // Internal ImGui functions to render text
   2660 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
   2661 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
   2662 {
   2663     ImGuiContext& g = *GImGui;
   2664     ImGuiWindow* window = g.CurrentWindow;
   2665 
   2666     // Hide anything after a '##' string
   2667     const char* text_display_end;
   2668     if (hide_text_after_hash)
   2669     {
   2670         text_display_end = FindRenderedTextEnd(text, text_end);
   2671     }
   2672     else
   2673     {
   2674         if (!text_end)
   2675             text_end = text + strlen(text); // FIXME-OPT
   2676         text_display_end = text_end;
   2677     }
   2678 
   2679     if (text != text_display_end)
   2680     {
   2681         window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
   2682         if (g.LogEnabled)
   2683             LogRenderedText(&pos, text, text_display_end);
   2684     }
   2685 }
   2686 
   2687 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
   2688 {
   2689     ImGuiContext& g = *GImGui;
   2690     ImGuiWindow* window = g.CurrentWindow;
   2691 
   2692     if (!text_end)
   2693         text_end = text + strlen(text); // FIXME-OPT
   2694 
   2695     if (text != text_end)
   2696     {
   2697         window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
   2698         if (g.LogEnabled)
   2699             LogRenderedText(&pos, text, text_end);
   2700     }
   2701 }
   2702 
   2703 // Default clip_rect uses (pos_min,pos_max)
   2704 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
   2705 void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
   2706 {
   2707     // Perform CPU side clipping for single clipped element to avoid using scissor state
   2708     ImVec2 pos = pos_min;
   2709     const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
   2710 
   2711     const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
   2712     const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
   2713     bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
   2714     if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
   2715         need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
   2716 
   2717     // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
   2718     if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
   2719     if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
   2720 
   2721     // Render
   2722     if (need_clipping)
   2723     {
   2724         ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
   2725         draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
   2726     }
   2727     else
   2728     {
   2729         draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
   2730     }
   2731 }
   2732 
   2733 void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
   2734 {
   2735     // Hide anything after a '##' string
   2736     const char* text_display_end = FindRenderedTextEnd(text, text_end);
   2737     const int text_len = (int)(text_display_end - text);
   2738     if (text_len == 0)
   2739         return;
   2740 
   2741     ImGuiContext& g = *GImGui;
   2742     ImGuiWindow* window = g.CurrentWindow;
   2743     RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
   2744     if (g.LogEnabled)
   2745         LogRenderedText(&pos_min, text, text_display_end);
   2746 }
   2747 
   2748 
   2749 // Another overly complex function until we reorganize everything into a nice all-in-one helper.
   2750 // 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.
   2751 // 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.
   2752 void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
   2753 {
   2754     ImGuiContext& g = *GImGui;
   2755     if (text_end_full == NULL)
   2756         text_end_full = FindRenderedTextEnd(text);
   2757     const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
   2758 
   2759     //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));
   2760     //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));
   2761     //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));
   2762     // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
   2763     if (text_size.x > pos_max.x - pos_min.x)
   2764     {
   2765         // Hello wo...
   2766         // |       |   |
   2767         // min   max   ellipsis_max
   2768         //          <-> this is generally some padding value
   2769 
   2770         const ImFont* font = draw_list->_Data->Font;
   2771         const float font_size = draw_list->_Data->FontSize;
   2772         const char* text_end_ellipsis = NULL;
   2773 
   2774         ImWchar ellipsis_char = font->EllipsisChar;
   2775         int ellipsis_char_count = 1;
   2776         if (ellipsis_char == (ImWchar)-1)
   2777         {
   2778             ellipsis_char = (ImWchar)'.';
   2779             ellipsis_char_count = 3;
   2780         }
   2781         const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
   2782 
   2783         float ellipsis_glyph_width = glyph->X1;                 // Width of the glyph with no padding on either side
   2784         float ellipsis_total_width = ellipsis_glyph_width;      // Full width of entire ellipsis
   2785 
   2786         if (ellipsis_char_count > 1)
   2787         {
   2788             // Full ellipsis size without free spacing after it.
   2789             const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize);
   2790             ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
   2791             ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
   2792         }
   2793 
   2794         // We can now claim the space between pos_max.x and ellipsis_max.x
   2795         const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f);
   2796         float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
   2797         if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
   2798         {
   2799             // Always display at least 1 character if there's no room for character + ellipsis
   2800             text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
   2801             text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
   2802         }
   2803         while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
   2804         {
   2805             // 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)
   2806             text_end_ellipsis--;
   2807             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
   2808         }
   2809 
   2810         // Render text, render ellipsis
   2811         RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
   2812         float ellipsis_x = pos_min.x + text_size_clipped_x;
   2813         if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x)
   2814             for (int i = 0; i < ellipsis_char_count; i++)
   2815             {
   2816                 font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char);
   2817                 ellipsis_x += ellipsis_glyph_width;
   2818             }
   2819     }
   2820     else
   2821     {
   2822         RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
   2823     }
   2824 
   2825     if (g.LogEnabled)
   2826         LogRenderedText(&pos_min, text, text_end_full);
   2827 }
   2828 
   2829 // Render a rectangle shaped with optional rounding and borders
   2830 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
   2831 {
   2832     ImGuiContext& g = *GImGui;
   2833     ImGuiWindow* window = g.CurrentWindow;
   2834     window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
   2835     const float border_size = g.Style.FrameBorderSize;
   2836     if (border && border_size > 0.0f)
   2837     {
   2838         window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
   2839         window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
   2840     }
   2841 }
   2842 
   2843 void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
   2844 {
   2845     ImGuiContext& g = *GImGui;
   2846     ImGuiWindow* window = g.CurrentWindow;
   2847     const float border_size = g.Style.FrameBorderSize;
   2848     if (border_size > 0.0f)
   2849     {
   2850         window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
   2851         window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
   2852     }
   2853 }
   2854 
   2855 void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)
   2856 {
   2857     ImGuiContext& g = *GImGui;
   2858     if (id != g.NavId)
   2859         return;
   2860     if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
   2861         return;
   2862     ImGuiWindow* window = g.CurrentWindow;
   2863     if (window->DC.NavHideHighlightOneFrame)
   2864         return;
   2865 
   2866     float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
   2867     ImRect display_rect = bb;
   2868     display_rect.ClipWith(window->ClipRect);
   2869     if (flags & ImGuiNavHighlightFlags_TypeDefault)
   2870     {
   2871         const float THICKNESS = 2.0f;
   2872         const float DISTANCE = 3.0f + THICKNESS * 0.5f;
   2873         display_rect.Expand(ImVec2(DISTANCE, DISTANCE));
   2874         bool fully_visible = window->ClipRect.Contains(display_rect);
   2875         if (!fully_visible)
   2876             window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
   2877         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, 0, THICKNESS);
   2878         if (!fully_visible)
   2879             window->DrawList->PopClipRect();
   2880     }
   2881     if (flags & ImGuiNavHighlightFlags_TypeThin)
   2882     {
   2883         window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, 0, 1.0f);
   2884     }
   2885 }
   2886 
   2887 //-----------------------------------------------------------------------------
   2888 // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
   2889 //-----------------------------------------------------------------------------
   2890 
   2891 // ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
   2892 ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name) : DrawListInst(NULL)
   2893 {
   2894     memset(this, 0, sizeof(*this));
   2895     Name = ImStrdup(name);
   2896     NameBufLen = (int)strlen(name) + 1;
   2897     ID = ImHashStr(name);
   2898     IDStack.push_back(ID);
   2899     MoveId = GetID("#MOVE");
   2900     ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
   2901     ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
   2902     AutoFitFramesX = AutoFitFramesY = -1;
   2903     AutoPosLastDirection = ImGuiDir_None;
   2904     SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
   2905     SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
   2906     LastFrameActive = -1;
   2907     LastTimeActive = -1.0f;
   2908     FontWindowScale = 1.0f;
   2909     SettingsOffset = -1;
   2910     DrawList = &DrawListInst;
   2911     DrawList->_Data = &context->DrawListSharedData;
   2912     DrawList->_OwnerName = Name;
   2913 }
   2914 
   2915 ImGuiWindow::~ImGuiWindow()
   2916 {
   2917     IM_ASSERT(DrawList == &DrawListInst);
   2918     IM_DELETE(Name);
   2919     for (int i = 0; i != ColumnsStorage.Size; i++)
   2920         ColumnsStorage[i].~ImGuiOldColumns();
   2921 }
   2922 
   2923 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
   2924 {
   2925     ImGuiID seed = IDStack.back();
   2926     ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
   2927     ImGui::KeepAliveID(id);
   2928 #ifdef IMGUI_ENABLE_TEST_ENGINE
   2929     ImGuiContext& g = *GImGui;
   2930     IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
   2931 #endif
   2932     return id;
   2933 }
   2934 
   2935 ImGuiID ImGuiWindow::GetID(const void* ptr)
   2936 {
   2937     ImGuiID seed = IDStack.back();
   2938     ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
   2939     ImGui::KeepAliveID(id);
   2940 #ifdef IMGUI_ENABLE_TEST_ENGINE
   2941     ImGuiContext& g = *GImGui;
   2942     IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
   2943 #endif
   2944     return id;
   2945 }
   2946 
   2947 ImGuiID ImGuiWindow::GetID(int n)
   2948 {
   2949     ImGuiID seed = IDStack.back();
   2950     ImGuiID id = ImHashData(&n, sizeof(n), seed);
   2951     ImGui::KeepAliveID(id);
   2952 #ifdef IMGUI_ENABLE_TEST_ENGINE
   2953     ImGuiContext& g = *GImGui;
   2954     IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
   2955 #endif
   2956     return id;
   2957 }
   2958 
   2959 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
   2960 {
   2961     ImGuiID seed = IDStack.back();
   2962     ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
   2963 #ifdef IMGUI_ENABLE_TEST_ENGINE
   2964     ImGuiContext& g = *GImGui;
   2965     IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
   2966 #endif
   2967     return id;
   2968 }
   2969 
   2970 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
   2971 {
   2972     ImGuiID seed = IDStack.back();
   2973     ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
   2974 #ifdef IMGUI_ENABLE_TEST_ENGINE
   2975     ImGuiContext& g = *GImGui;
   2976     IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
   2977 #endif
   2978     return id;
   2979 }
   2980 
   2981 ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
   2982 {
   2983     ImGuiID seed = IDStack.back();
   2984     ImGuiID id = ImHashData(&n, sizeof(n), seed);
   2985 #ifdef IMGUI_ENABLE_TEST_ENGINE
   2986     ImGuiContext& g = *GImGui;
   2987     IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
   2988 #endif
   2989     return id;
   2990 }
   2991 
   2992 // This is only used in rare/specific situations to manufacture an ID out of nowhere.
   2993 ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
   2994 {
   2995     ImGuiID seed = IDStack.back();
   2996     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) };
   2997     ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
   2998     ImGui::KeepAliveID(id);
   2999     return id;
   3000 }
   3001 
   3002 static void SetCurrentWindow(ImGuiWindow* window)
   3003 {
   3004     ImGuiContext& g = *GImGui;
   3005     g.CurrentWindow = window;
   3006     g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL;
   3007     if (window)
   3008         g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
   3009 }
   3010 
   3011 void ImGui::GcCompactTransientMiscBuffers()
   3012 {
   3013     ImGuiContext& g = *GImGui;
   3014     g.ItemFlagsStack.clear();
   3015     g.GroupStack.clear();
   3016     TableGcCompactSettings();
   3017 }
   3018 
   3019 // Free up/compact internal window buffers, we can use this when a window becomes unused.
   3020 // Not freed:
   3021 // - ImGuiWindow, ImGuiWindowSettings, Name, StateStorage, ColumnsStorage (may hold useful data)
   3022 // This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
   3023 void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
   3024 {
   3025     window->MemoryCompacted = true;
   3026     window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
   3027     window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
   3028     window->IDStack.clear();
   3029     window->DrawList->_ClearFreeMemory();
   3030     window->DC.ChildWindows.clear();
   3031     window->DC.ItemWidthStack.clear();
   3032     window->DC.TextWrapPosStack.clear();
   3033 }
   3034 
   3035 void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
   3036 {
   3037     // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
   3038     // The other buffers tends to amortize much faster.
   3039     window->MemoryCompacted = false;
   3040     window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);
   3041     window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);
   3042     window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;
   3043 }
   3044 
   3045 void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
   3046 {
   3047     ImGuiContext& g = *GImGui;
   3048     g.ActiveIdIsJustActivated = (g.ActiveId != id);
   3049     if (g.ActiveIdIsJustActivated)
   3050     {
   3051         g.ActiveIdTimer = 0.0f;
   3052         g.ActiveIdHasBeenPressedBefore = false;
   3053         g.ActiveIdHasBeenEditedBefore = false;
   3054         g.ActiveIdMouseButton = -1;
   3055         if (id != 0)
   3056         {
   3057             g.LastActiveId = id;
   3058             g.LastActiveIdTimer = 0.0f;
   3059         }
   3060     }
   3061     g.ActiveId = id;
   3062     g.ActiveIdAllowOverlap = false;
   3063     g.ActiveIdNoClearOnFocusLoss = false;
   3064     g.ActiveIdWindow = window;
   3065     g.ActiveIdHasBeenEditedThisFrame = false;
   3066     if (id)
   3067     {
   3068         g.ActiveIdIsAlive = id;
   3069         g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
   3070     }
   3071 
   3072     // Clear declaration of inputs claimed by the widget
   3073     // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
   3074     g.ActiveIdUsingMouseWheel = false;
   3075     g.ActiveIdUsingNavDirMask = 0x00;
   3076     g.ActiveIdUsingNavInputMask = 0x00;
   3077     g.ActiveIdUsingKeyInputMask = 0x00;
   3078 }
   3079 
   3080 void ImGui::ClearActiveID()
   3081 {
   3082     SetActiveID(0, NULL); // g.ActiveId = 0;
   3083 }
   3084 
   3085 void ImGui::SetHoveredID(ImGuiID id)
   3086 {
   3087     ImGuiContext& g = *GImGui;
   3088     g.HoveredId = id;
   3089     g.HoveredIdAllowOverlap = false;
   3090     g.HoveredIdUsingMouseWheel = false;
   3091     if (id != 0 && g.HoveredIdPreviousFrame != id)
   3092         g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;
   3093 }
   3094 
   3095 ImGuiID ImGui::GetHoveredID()
   3096 {
   3097     ImGuiContext& g = *GImGui;
   3098     return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
   3099 }
   3100 
   3101 void ImGui::KeepAliveID(ImGuiID id)
   3102 {
   3103     ImGuiContext& g = *GImGui;
   3104     if (g.ActiveId == id)
   3105         g.ActiveIdIsAlive = id;
   3106     if (g.ActiveIdPreviousFrame == id)
   3107         g.ActiveIdPreviousFrameIsAlive = true;
   3108 }
   3109 
   3110 void ImGui::MarkItemEdited(ImGuiID id)
   3111 {
   3112     // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
   3113     // 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.
   3114     ImGuiContext& g = *GImGui;
   3115     IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
   3116     IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
   3117     //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
   3118     g.ActiveIdHasBeenEditedThisFrame = true;
   3119     g.ActiveIdHasBeenEditedBefore = true;
   3120     g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
   3121 }
   3122 
   3123 static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
   3124 {
   3125     // An active popup disable hovering on other windows (apart from its own children)
   3126     // FIXME-OPT: This could be cached/stored within the window.
   3127     ImGuiContext& g = *GImGui;
   3128     if (g.NavWindow)
   3129         if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
   3130             if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
   3131             {
   3132                 // For the purpose of those flags we differentiate "standard popup" from "modal popup"
   3133                 // NB: The order of those two tests is important because Modal windows are also Popups.
   3134                 if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
   3135                     return false;
   3136                 if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
   3137                     return false;
   3138             }
   3139     return true;
   3140 }
   3141 
   3142 // This is roughly matching the behavior of internal-facing ItemHoverable()
   3143 // - 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()
   3144 // - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
   3145 bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
   3146 {
   3147     ImGuiContext& g = *GImGui;
   3148     ImGuiWindow* window = g.CurrentWindow;
   3149     if (g.NavDisableMouseHover && !g.NavDisableHighlight)
   3150         return IsItemFocused();
   3151 
   3152     // Test for bounding box overlap, as updated as ItemAdd()
   3153     ImGuiItemStatusFlags status_flags = window->DC.LastItemStatusFlags;
   3154     if (!(status_flags & ImGuiItemStatusFlags_HoveredRect))
   3155         return false;
   3156     IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0);   // Flags not supported by this function
   3157 
   3158     // Test if we are hovering the right window (our window could be behind another window)
   3159     // [2021/03/02] Reworked / reverted the revert, finally. Note we want e.g. BeginGroup/ItemAdd/EndGroup to work as well. (#3851)
   3160     // [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
   3161     // to use IsItemHovered() after EndChild() itself. Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was
   3162     // the test that has been running for a long while.
   3163     if (g.HoveredWindow != window && (status_flags & ImGuiItemStatusFlags_HoveredWindow) == 0)
   3164         if ((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0)
   3165             return false;
   3166 
   3167     // Test if another item is active (e.g. being dragged)
   3168     if ((flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) == 0)
   3169         if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
   3170             return false;
   3171 
   3172     // Test if interactions on this window are blocked by an active popup or modal.
   3173     // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
   3174     if (!IsWindowContentHoverable(window, flags))
   3175         return false;
   3176 
   3177     // Test if the item is disabled
   3178     if ((g.CurrentItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
   3179         return false;
   3180 
   3181     // Special handling for calling after Begin() which represent the title bar or tab.
   3182     // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
   3183     if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
   3184         return false;
   3185     return true;
   3186 }
   3187 
   3188 // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
   3189 bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
   3190 {
   3191     ImGuiContext& g = *GImGui;
   3192     if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
   3193         return false;
   3194 
   3195     ImGuiWindow* window = g.CurrentWindow;
   3196     if (g.HoveredWindow != window)
   3197         return false;
   3198     if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
   3199         return false;
   3200     if (!IsMouseHoveringRect(bb.Min, bb.Max))
   3201         return false;
   3202     if (g.NavDisableMouseHover)
   3203         return false;
   3204     if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (g.CurrentItemFlags & ImGuiItemFlags_Disabled))
   3205     {
   3206         g.HoveredIdDisabled = true;
   3207         return false;
   3208     }
   3209 
   3210     // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level
   3211     // hover test in widgets code. We could also decide to split this function is two.
   3212     if (id != 0)
   3213     {
   3214         SetHoveredID(id);
   3215 
   3216         // [DEBUG] Item Picker tool!
   3217         // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making
   3218         // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered
   3219         // items if we perform the test in ItemAdd(), but that would incur a small runtime cost.
   3220         // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd().
   3221         if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id)
   3222             GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
   3223         if (g.DebugItemPickerBreakId == id)
   3224             IM_DEBUG_BREAK();
   3225     }
   3226 
   3227     return true;
   3228 }
   3229 
   3230 bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
   3231 {
   3232     ImGuiContext& g = *GImGui;
   3233     ImGuiWindow* window = g.CurrentWindow;
   3234     if (!bb.Overlaps(window->ClipRect))
   3235         if (id == 0 || (id != g.ActiveId && id != g.NavId))
   3236             if (clip_even_when_logged || !g.LogEnabled)
   3237                 return true;
   3238     return false;
   3239 }
   3240 
   3241 // This is also inlined in ItemAdd()
   3242 // Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect!
   3243 void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
   3244 {
   3245     window->DC.LastItemId = item_id;
   3246     window->DC.LastItemStatusFlags = item_flags;
   3247     window->DC.LastItemRect = item_rect;
   3248 }
   3249 
   3250 // Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
   3251 void ImGui::ItemFocusable(ImGuiWindow* window, ImGuiID id)
   3252 {
   3253     ImGuiContext& g = *GImGui;
   3254     IM_ASSERT(id != 0 && id == window->DC.LastItemId);
   3255 
   3256     // Increment counters
   3257     // FIXME: ImGuiItemFlags_Disabled should disable more.
   3258     const bool is_tab_stop = (g.CurrentItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
   3259     window->DC.FocusCounterRegular++;
   3260     if (is_tab_stop)
   3261     {
   3262         window->DC.FocusCounterTabStop++;
   3263         if (g.NavId == id)
   3264             g.NavIdTabCounter = window->DC.FocusCounterTabStop;
   3265     }
   3266 
   3267     // Process TAB/Shift-TAB to tab *OUT* of the currently focused item.
   3268     // (Note that we can always TAB out of a widget that doesn't allow tabbing in)
   3269     if (g.ActiveId == id && g.TabFocusPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.TabFocusRequestNextWindow == NULL)
   3270     {
   3271         g.TabFocusRequestNextWindow = window;
   3272         g.TabFocusRequestNextCounterTabStop = 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.
   3273     }
   3274 
   3275     // Handle focus requests
   3276     if (g.TabFocusRequestCurrWindow == window)
   3277     {
   3278         if (window->DC.FocusCounterRegular == g.TabFocusRequestCurrCounterRegular)
   3279         {
   3280             window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByCode;
   3281             return;
   3282         }
   3283         if (is_tab_stop && window->DC.FocusCounterTabStop == g.TabFocusRequestCurrCounterTabStop)
   3284         {
   3285             g.NavJustTabbedId = id;
   3286             window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_FocusedByTabbing;
   3287             return;
   3288         }
   3289 
   3290         // If another item is about to be focused, we clear our own active id
   3291         if (g.ActiveId == id)
   3292             ClearActiveID();
   3293     }
   3294 }
   3295 
   3296 float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
   3297 {
   3298     if (wrap_pos_x < 0.0f)
   3299         return 0.0f;
   3300 
   3301     ImGuiContext& g = *GImGui;
   3302     ImGuiWindow* window = g.CurrentWindow;
   3303     if (wrap_pos_x == 0.0f)
   3304     {
   3305         // We could decide to setup a default wrapping max point for auto-resizing windows,
   3306         // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function?
   3307         //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize))
   3308         //    wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x);
   3309         //else
   3310         wrap_pos_x = window->WorkRect.Max.x;
   3311     }
   3312     else if (wrap_pos_x > 0.0f)
   3313     {
   3314         wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
   3315     }
   3316 
   3317     return ImMax(wrap_pos_x - pos.x, 1.0f);
   3318 }
   3319 
   3320 // IM_ALLOC() == ImGui::MemAlloc()
   3321 void* ImGui::MemAlloc(size_t size)
   3322 {
   3323     if (ImGuiContext* ctx = GImGui)
   3324         ctx->IO.MetricsActiveAllocations++;
   3325     return (*GImAllocatorAllocFunc)(size, GImAllocatorUserData);
   3326 }
   3327 
   3328 // IM_FREE() == ImGui::MemFree()
   3329 void ImGui::MemFree(void* ptr)
   3330 {
   3331     if (ptr)
   3332         if (ImGuiContext* ctx = GImGui)
   3333             ctx->IO.MetricsActiveAllocations--;
   3334     return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData);
   3335 }
   3336 
   3337 const char* ImGui::GetClipboardText()
   3338 {
   3339     ImGuiContext& g = *GImGui;
   3340     return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : "";
   3341 }
   3342 
   3343 void ImGui::SetClipboardText(const char* text)
   3344 {
   3345     ImGuiContext& g = *GImGui;
   3346     if (g.IO.SetClipboardTextFn)
   3347         g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text);
   3348 }
   3349 
   3350 const char* ImGui::GetVersion()
   3351 {
   3352     return IMGUI_VERSION;
   3353 }
   3354 
   3355 // Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
   3356 // 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
   3357 ImGuiContext* ImGui::GetCurrentContext()
   3358 {
   3359     return GImGui;
   3360 }
   3361 
   3362 void ImGui::SetCurrentContext(ImGuiContext* ctx)
   3363 {
   3364 #ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
   3365     IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
   3366 #else
   3367     GImGui = ctx;
   3368 #endif
   3369 }
   3370 
   3371 void ImGui::SetAllocatorFunctions(ImGuiMemAllocFunc alloc_func, ImGuiMemFreeFunc free_func, void* user_data)
   3372 {
   3373     GImAllocatorAllocFunc = alloc_func;
   3374     GImAllocatorFreeFunc = free_func;
   3375     GImAllocatorUserData = user_data;
   3376 }
   3377 
   3378 // This is provided to facilitate copying allocators from one static/DLL boundary to another (e.g. retrieve default allocator of your executable address space)
   3379 void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeFunc* p_free_func, void** p_user_data)
   3380 {
   3381     *p_alloc_func = GImAllocatorAllocFunc;
   3382     *p_free_func = GImAllocatorFreeFunc;
   3383     *p_user_data = GImAllocatorUserData;
   3384 }
   3385 
   3386 ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
   3387 {
   3388     ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
   3389     if (GImGui == NULL)
   3390         SetCurrentContext(ctx);
   3391     Initialize(ctx);
   3392     return ctx;
   3393 }
   3394 
   3395 void ImGui::DestroyContext(ImGuiContext* ctx)
   3396 {
   3397     if (ctx == NULL)
   3398         ctx = GImGui;
   3399     Shutdown(ctx);
   3400     if (GImGui == ctx)
   3401         SetCurrentContext(NULL);
   3402     IM_DELETE(ctx);
   3403 }
   3404 
   3405 // No specific ordering/dependency support, will see as needed
   3406 ImGuiID ImGui::AddContextHook(ImGuiContext* ctx, const ImGuiContextHook* hook)
   3407 {
   3408     ImGuiContext& g = *ctx;
   3409     IM_ASSERT(hook->Callback != NULL && hook->HookId == 0 && hook->Type != ImGuiContextHookType_PendingRemoval_);
   3410     g.Hooks.push_back(*hook);
   3411     g.Hooks.back().HookId = ++g.HookIdNext;
   3412     return g.HookIdNext;
   3413 }
   3414 
   3415 // Deferred removal, avoiding issue with changing vector while iterating it
   3416 void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id)
   3417 {
   3418     ImGuiContext& g = *ctx;
   3419     IM_ASSERT(hook_id != 0);
   3420     for (int n = 0; n < g.Hooks.Size; n++)
   3421         if (g.Hooks[n].HookId == hook_id)
   3422             g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_;
   3423 }
   3424 
   3425 // Call context hooks (used by e.g. test engine)
   3426 // We assume a small number of hooks so all stored in same array
   3427 void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type)
   3428 {
   3429     ImGuiContext& g = *ctx;
   3430     for (int n = 0; n < g.Hooks.Size; n++)
   3431         if (g.Hooks[n].Type == hook_type)
   3432             g.Hooks[n].Callback(&g, &g.Hooks[n]);
   3433 }
   3434 
   3435 ImGuiIO& ImGui::GetIO()
   3436 {
   3437     IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
   3438     return GImGui->IO;
   3439 }
   3440 
   3441 // Pass this to your backend rendering function! Valid after Render() and until the next call to NewFrame()
   3442 ImDrawData* ImGui::GetDrawData()
   3443 {
   3444     ImGuiContext& g = *GImGui;
   3445     ImGuiViewportP* viewport = g.Viewports[0];
   3446     return viewport->DrawDataP.Valid ? &viewport->DrawDataP : NULL;
   3447 }
   3448 
   3449 double ImGui::GetTime()
   3450 {
   3451     return GImGui->Time;
   3452 }
   3453 
   3454 int ImGui::GetFrameCount()
   3455 {
   3456     return GImGui->FrameCount;
   3457 }
   3458 
   3459 static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name)
   3460 {
   3461     // Create the draw list on demand, because they are not frequently used for all viewports
   3462     ImGuiContext& g = *GImGui;
   3463     IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists));
   3464     ImDrawList* draw_list = viewport->DrawLists[drawlist_no];
   3465     if (draw_list == NULL)
   3466     {
   3467         draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData);
   3468         draw_list->_OwnerName = drawlist_name;
   3469         viewport->DrawLists[drawlist_no] = draw_list;
   3470     }
   3471 
   3472     // Our ImDrawList system requires that there is always a command
   3473     if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount)
   3474     {
   3475         draw_list->_ResetForNewFrame();
   3476         draw_list->PushTextureID(g.IO.Fonts->TexID);
   3477         draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
   3478         viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount;
   3479     }
   3480     return draw_list;
   3481 }
   3482 
   3483 ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport)
   3484 {
   3485     return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background");
   3486 }
   3487 
   3488 ImDrawList* ImGui::GetBackgroundDrawList()
   3489 {
   3490     ImGuiContext& g = *GImGui;
   3491     return GetBackgroundDrawList(g.Viewports[0]);
   3492 }
   3493 
   3494 ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport)
   3495 {
   3496     return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
   3497 }
   3498 
   3499 ImDrawList* ImGui::GetForegroundDrawList()
   3500 {
   3501     ImGuiContext& g = *GImGui;
   3502     return GetForegroundDrawList(g.Viewports[0]);
   3503 }
   3504 
   3505 ImDrawListSharedData* ImGui::GetDrawListSharedData()
   3506 {
   3507     return &GImGui->DrawListSharedData;
   3508 }
   3509 
   3510 void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
   3511 {
   3512     // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
   3513     // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
   3514     // This is because we want ActiveId to be set even when the window is not permitted to move.
   3515     ImGuiContext& g = *GImGui;
   3516     FocusWindow(window);
   3517     SetActiveID(window->MoveId, window);
   3518     g.NavDisableHighlight = true;
   3519     g.ActiveIdNoClearOnFocusLoss = true;
   3520     g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos;
   3521 
   3522     bool can_move_window = true;
   3523     if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove))
   3524         can_move_window = false;
   3525     if (can_move_window)
   3526         g.MovingWindow = window;
   3527 }
   3528 
   3529 // Handle mouse moving window
   3530 // Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
   3531 // FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId.
   3532 // This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs,
   3533 // but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other.
   3534 void ImGui::UpdateMouseMovingWindowNewFrame()
   3535 {
   3536     ImGuiContext& g = *GImGui;
   3537     if (g.MovingWindow != NULL)
   3538     {
   3539         // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
   3540         // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
   3541         KeepAliveID(g.ActiveId);
   3542         IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);
   3543         ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
   3544         if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
   3545         {
   3546             ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
   3547             if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
   3548             {
   3549                 MarkIniSettingsDirty(moving_window);
   3550                 SetWindowPos(moving_window, pos, ImGuiCond_Always);
   3551             }
   3552             FocusWindow(g.MovingWindow);
   3553         }
   3554         else
   3555         {
   3556             ClearActiveID();
   3557             g.MovingWindow = NULL;
   3558         }
   3559     }
   3560     else
   3561     {
   3562         // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
   3563         if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
   3564         {
   3565             KeepAliveID(g.ActiveId);
   3566             if (!g.IO.MouseDown[0])
   3567                 ClearActiveID();
   3568         }
   3569     }
   3570 }
   3571 
   3572 // Initiate moving window when clicking on empty space or title bar.
   3573 // Handle left-click and right-click focus.
   3574 void ImGui::UpdateMouseMovingWindowEndFrame()
   3575 {
   3576     ImGuiContext& g = *GImGui;
   3577     if (g.ActiveId != 0 || g.HoveredId != 0)
   3578         return;
   3579 
   3580     // Unless we just made a window/popup appear
   3581     if (g.NavWindow && g.NavWindow->Appearing)
   3582         return;
   3583 
   3584     // Click on empty space to focus window and start moving
   3585     // (after we're done with all our widgets)
   3586     if (g.IO.MouseClicked[0])
   3587     {
   3588         // Handle the edge case of a popup being closed while clicking in its empty space.
   3589         // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more.
   3590         ImGuiWindow* root_window = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
   3591         const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);
   3592 
   3593         if (root_window != NULL && !is_closed_popup)
   3594         {
   3595             StartMouseMovingWindow(g.HoveredWindow); //-V595
   3596 
   3597             // Cancel moving if clicked outside of title bar
   3598             if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar))
   3599                 if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
   3600                     g.MovingWindow = NULL;
   3601 
   3602             // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already)
   3603             if (g.HoveredIdDisabled)
   3604                 g.MovingWindow = NULL;
   3605         }
   3606         else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
   3607         {
   3608             // Clicking on void disable focus
   3609             FocusWindow(NULL);
   3610         }
   3611     }
   3612 
   3613     // With right mouse button we close popups without changing focus based on where the mouse is aimed
   3614     // Instead, focus will be restored to the window under the bottom-most closed popup.
   3615     // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
   3616     if (g.IO.MouseClicked[1])
   3617     {
   3618         // Find the top-most window between HoveredWindow and the top-most Modal Window.
   3619         // This is where we can trim the popup stack.
   3620         ImGuiWindow* modal = GetTopMostPopupModal();
   3621         bool hovered_window_above_modal = g.HoveredWindow && IsWindowAbove(g.HoveredWindow, modal);
   3622         ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);
   3623     }
   3624 }
   3625 
   3626 static bool IsWindowActiveAndVisible(ImGuiWindow* window)
   3627 {
   3628     return (window->Active) && (!window->Hidden);
   3629 }
   3630 
   3631 static void ImGui::UpdateMouseInputs()
   3632 {
   3633     ImGuiContext& g = *GImGui;
   3634 
   3635     // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
   3636     if (IsMousePosValid(&g.IO.MousePos))
   3637         g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos);
   3638 
   3639     // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
   3640     if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
   3641         g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
   3642     else
   3643         g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
   3644     if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
   3645         g.NavDisableMouseHover = false;
   3646 
   3647     g.IO.MousePosPrev = g.IO.MousePos;
   3648     for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
   3649     {
   3650         g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
   3651         g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
   3652         g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
   3653         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;
   3654         g.IO.MouseDoubleClicked[i] = false;
   3655         if (g.IO.MouseClicked[i])
   3656         {
   3657             if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime)
   3658             {
   3659                 ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
   3660                 if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
   3661                     g.IO.MouseDoubleClicked[i] = true;
   3662                 g.IO.MouseClickedTime[i] = -g.IO.MouseDoubleClickTime * 2.0f; // Mark as "old enough" so the third click isn't turned into a double-click
   3663             }
   3664             else
   3665             {
   3666                 g.IO.MouseClickedTime[i] = g.Time;
   3667             }
   3668             g.IO.MouseClickedPos[i] = g.IO.MousePos;
   3669             g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i];
   3670             g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
   3671             g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
   3672         }
   3673         else if (g.IO.MouseDown[i])
   3674         {
   3675             // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold
   3676             ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
   3677             g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos));
   3678             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);
   3679             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);
   3680         }
   3681         if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i])
   3682             g.IO.MouseDownWasDoubleClick[i] = false;
   3683         if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
   3684             g.NavDisableMouseHover = false;
   3685     }
   3686 }
   3687 
   3688 static void StartLockWheelingWindow(ImGuiWindow* window)
   3689 {
   3690     ImGuiContext& g = *GImGui;
   3691     if (g.WheelingWindow == window)
   3692         return;
   3693     g.WheelingWindow = window;
   3694     g.WheelingWindowRefMousePos = g.IO.MousePos;
   3695     g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER;
   3696 }
   3697 
   3698 void ImGui::UpdateMouseWheel()
   3699 {
   3700     ImGuiContext& g = *GImGui;
   3701 
   3702     // Reset the locked window if we move the mouse or after the timer elapses
   3703     if (g.WheelingWindow != NULL)
   3704     {
   3705         g.WheelingWindowTimer -= g.IO.DeltaTime;
   3706         if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)
   3707             g.WheelingWindowTimer = 0.0f;
   3708         if (g.WheelingWindowTimer <= 0.0f)
   3709         {
   3710             g.WheelingWindow = NULL;
   3711             g.WheelingWindowTimer = 0.0f;
   3712         }
   3713     }
   3714 
   3715     if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
   3716         return;
   3717 
   3718     if ((g.ActiveId != 0 && g.ActiveIdUsingMouseWheel) || (g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrameUsingMouseWheel))
   3719         return;
   3720 
   3721     ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
   3722     if (!window || window->Collapsed)
   3723         return;
   3724 
   3725     // Zoom / Scale window
   3726     // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
   3727     if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
   3728     {
   3729         StartLockWheelingWindow(window);
   3730         const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
   3731         const float scale = new_font_scale / window->FontWindowScale;
   3732         window->FontWindowScale = new_font_scale;
   3733         if (window == window->RootWindow)
   3734         {
   3735             const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
   3736             SetWindowPos(window, window->Pos + offset, 0);
   3737             window->Size = ImFloor(window->Size * scale);
   3738             window->SizeFull = ImFloor(window->SizeFull * scale);
   3739         }
   3740         return;
   3741     }
   3742 
   3743     // Mouse wheel scrolling
   3744     // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent
   3745     if (g.IO.KeyCtrl)
   3746         return;
   3747 
   3748     // As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
   3749     // (we avoid doing it on OSX as it the OS input layer handles this already)
   3750     const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
   3751     const float wheel_y = swap_axis ? 0.0f : g.IO.MouseWheel;
   3752     const float wheel_x = swap_axis ? g.IO.MouseWheel : g.IO.MouseWheelH;
   3753 
   3754     // Vertical Mouse Wheel scrolling
   3755     if (wheel_y != 0.0f)
   3756     {
   3757         StartLockWheelingWindow(window);
   3758         while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
   3759             window = window->ParentWindow;
   3760         if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
   3761         {
   3762             float max_step = window->InnerRect.GetHeight() * 0.67f;
   3763             float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
   3764             SetScrollY(window, window->Scroll.y - wheel_y * scroll_step);
   3765         }
   3766     }
   3767 
   3768     // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
   3769     if (wheel_x != 0.0f)
   3770     {
   3771         StartLockWheelingWindow(window);
   3772         while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
   3773             window = window->ParentWindow;
   3774         if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
   3775         {
   3776             float max_step = window->InnerRect.GetWidth() * 0.67f;
   3777             float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
   3778             SetScrollX(window, window->Scroll.x - wheel_x * scroll_step);
   3779         }
   3780     }
   3781 }
   3782 
   3783 void ImGui::UpdateTabFocus()
   3784 {
   3785     ImGuiContext& g = *GImGui;
   3786 
   3787     // Pressing TAB activate widget focus
   3788     g.TabFocusPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
   3789     if (g.ActiveId == 0 && g.TabFocusPressed)
   3790     {
   3791         // - This path is only taken when no widget are active/tabbed-into yet.
   3792         //   Subsequent tabbing will be processed by FocusableItemRegister()
   3793         // - Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
   3794         //   manipulate the Next fields here even though they will be turned into Curr fields below.
   3795         g.TabFocusRequestNextWindow = g.NavWindow;
   3796         g.TabFocusRequestNextCounterRegular = INT_MAX;
   3797         if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
   3798             g.TabFocusRequestNextCounterTabStop = g.NavIdTabCounter + (g.IO.KeyShift ? -1 : 0);
   3799         else
   3800             g.TabFocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
   3801     }
   3802 
   3803     // Turn queued focus request into current one
   3804     g.TabFocusRequestCurrWindow = NULL;
   3805     g.TabFocusRequestCurrCounterRegular = g.TabFocusRequestCurrCounterTabStop = INT_MAX;
   3806     if (g.TabFocusRequestNextWindow != NULL)
   3807     {
   3808         ImGuiWindow* window = g.TabFocusRequestNextWindow;
   3809         g.TabFocusRequestCurrWindow = window;
   3810         if (g.TabFocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1)
   3811             g.TabFocusRequestCurrCounterRegular = ImModPositive(g.TabFocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1);
   3812         if (g.TabFocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1)
   3813             g.TabFocusRequestCurrCounterTabStop = ImModPositive(g.TabFocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1);
   3814         g.TabFocusRequestNextWindow = NULL;
   3815         g.TabFocusRequestNextCounterRegular = g.TabFocusRequestNextCounterTabStop = INT_MAX;
   3816     }
   3817 
   3818     g.NavIdTabCounter = INT_MAX;
   3819 }
   3820 
   3821 // 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)
   3822 void ImGui::UpdateHoveredWindowAndCaptureFlags()
   3823 {
   3824     ImGuiContext& g = *GImGui;
   3825     g.WindowsHoverPadding = ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_HOVER_PADDING, WINDOWS_HOVER_PADDING));
   3826 
   3827     // Find the window hovered by mouse:
   3828     // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
   3829     // - 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.
   3830     // - 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.
   3831     bool clear_hovered_windows = false;
   3832     FindHoveredWindow();
   3833 
   3834     // Modal windows prevents mouse from hovering behind them.
   3835     ImGuiWindow* modal_window = GetTopMostPopupModal();
   3836     if (modal_window && g.HoveredWindow && !IsWindowChildOf(g.HoveredWindow->RootWindow, modal_window))
   3837         clear_hovered_windows = true;
   3838 
   3839     // Disabled mouse?
   3840     if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
   3841         clear_hovered_windows = true;
   3842 
   3843     // 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.
   3844     int mouse_earliest_button_down = -1;
   3845     bool mouse_any_down = false;
   3846     for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
   3847     {
   3848         if (g.IO.MouseClicked[i])
   3849             g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (g.OpenPopupStack.Size > 0);
   3850         mouse_any_down |= g.IO.MouseDown[i];
   3851         if (g.IO.MouseDown[i])
   3852             if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
   3853                 mouse_earliest_button_down = i;
   3854     }
   3855     const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
   3856 
   3857     // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
   3858     // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
   3859     const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
   3860     if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
   3861         clear_hovered_windows = true;
   3862 
   3863     if (clear_hovered_windows)
   3864         g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL;
   3865 
   3866     // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app)
   3867     if (g.WantCaptureMouseNextFrame != -1)
   3868         g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
   3869     else
   3870         g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.OpenPopupStack.Size > 0);
   3871 
   3872     // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app)
   3873     if (g.WantCaptureKeyboardNextFrame != -1)
   3874         g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
   3875     else
   3876         g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
   3877     if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
   3878         g.IO.WantCaptureKeyboard = true;
   3879 
   3880     // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
   3881     g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
   3882 }
   3883 
   3884 ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
   3885 {
   3886     ImGuiContext& g = *GImGui;
   3887     ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None;
   3888     if (g.IO.KeyCtrl)   { key_mod_flags |= ImGuiKeyModFlags_Ctrl; }
   3889     if (g.IO.KeyShift)  { key_mod_flags |= ImGuiKeyModFlags_Shift; }
   3890     if (g.IO.KeyAlt)    { key_mod_flags |= ImGuiKeyModFlags_Alt; }
   3891     if (g.IO.KeySuper)  { key_mod_flags |= ImGuiKeyModFlags_Super; }
   3892     return key_mod_flags;
   3893 }
   3894 
   3895 void ImGui::NewFrame()
   3896 {
   3897     IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
   3898     ImGuiContext& g = *GImGui;
   3899 
   3900     // Remove pending delete hooks before frame start.
   3901     // This deferred removal avoid issues of removal while iterating the hook vector
   3902     for (int n = g.Hooks.Size - 1; n >= 0; n--)
   3903         if (g.Hooks[n].Type == ImGuiContextHookType_PendingRemoval_)
   3904             g.Hooks.erase(&g.Hooks[n]);
   3905 
   3906     CallContextHooks(&g, ImGuiContextHookType_NewFramePre);
   3907 
   3908     // Check and assert for various common IO and Configuration mistakes
   3909     ErrorCheckNewFrameSanityChecks();
   3910 
   3911     // Load settings on first frame, save settings when modified (after a delay)
   3912     UpdateSettings();
   3913 
   3914     g.Time += g.IO.DeltaTime;
   3915     g.WithinFrameScope = true;
   3916     g.FrameCount += 1;
   3917     g.TooltipOverrideCount = 0;
   3918     g.WindowsActiveCount = 0;
   3919     g.MenusIdSubmittedThisFrame.resize(0);
   3920 
   3921     // Calculate frame-rate for the user, as a purely luxurious feature
   3922     g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
   3923     g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
   3924     g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
   3925     g.FramerateSecPerFrameCount = ImMin(g.FramerateSecPerFrameCount + 1, IM_ARRAYSIZE(g.FramerateSecPerFrame));
   3926     g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)g.FramerateSecPerFrameCount)) : FLT_MAX;
   3927 
   3928     UpdateViewportsNewFrame();
   3929 
   3930     // Setup current font and draw list shared data
   3931     g.IO.Fonts->Locked = true;
   3932     SetCurrentFont(GetDefaultFont());
   3933     IM_ASSERT(g.Font->IsLoaded());
   3934     ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
   3935     for (int n = 0; n < g.Viewports.Size; n++)
   3936         virtual_space.Add(g.Viewports[n]->GetMainRect());
   3937     g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();
   3938     g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
   3939     g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError);
   3940     g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
   3941     if (g.Style.AntiAliasedLines)
   3942         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
   3943     if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines))
   3944         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex;
   3945     if (g.Style.AntiAliasedFill)
   3946         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
   3947     if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
   3948         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
   3949 
   3950     // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
   3951     for (int n = 0; n < g.Viewports.Size; n++)
   3952     {
   3953         ImGuiViewportP* viewport = g.Viewports[n];
   3954         viewport->DrawDataP.Clear();
   3955     }
   3956 
   3957     // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
   3958     if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
   3959         KeepAliveID(g.DragDropPayload.SourceId);
   3960 
   3961     // Update HoveredId data
   3962     if (!g.HoveredIdPreviousFrame)
   3963         g.HoveredIdTimer = 0.0f;
   3964     if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
   3965         g.HoveredIdNotActiveTimer = 0.0f;
   3966     if (g.HoveredId)
   3967         g.HoveredIdTimer += g.IO.DeltaTime;
   3968     if (g.HoveredId && g.ActiveId != g.HoveredId)
   3969         g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
   3970     g.HoveredIdPreviousFrame = g.HoveredId;
   3971     g.HoveredIdPreviousFrameUsingMouseWheel = g.HoveredIdUsingMouseWheel;
   3972     g.HoveredId = 0;
   3973     g.HoveredIdAllowOverlap = false;
   3974     g.HoveredIdUsingMouseWheel = false;
   3975     g.HoveredIdDisabled = false;
   3976 
   3977     // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
   3978     if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
   3979         ClearActiveID();
   3980     if (g.ActiveId)
   3981         g.ActiveIdTimer += g.IO.DeltaTime;
   3982     g.LastActiveIdTimer += g.IO.DeltaTime;
   3983     g.ActiveIdPreviousFrame = g.ActiveId;
   3984     g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
   3985     g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
   3986     g.ActiveIdIsAlive = 0;
   3987     g.ActiveIdHasBeenEditedThisFrame = false;
   3988     g.ActiveIdPreviousFrameIsAlive = false;
   3989     g.ActiveIdIsJustActivated = false;
   3990     if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
   3991         g.TempInputId = 0;
   3992     if (g.ActiveId == 0)
   3993     {
   3994         g.ActiveIdUsingNavDirMask = 0x00;
   3995         g.ActiveIdUsingNavInputMask = 0x00;
   3996         g.ActiveIdUsingKeyInputMask = 0x00;
   3997     }
   3998 
   3999     // Drag and drop
   4000     g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
   4001     g.DragDropAcceptIdCurr = 0;
   4002     g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
   4003     g.DragDropWithinSource = false;
   4004     g.DragDropWithinTarget = false;
   4005     g.DragDropHoldJustPressedId = 0;
   4006 
   4007     // Update keyboard input state
   4008     // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools
   4009     g.IO.KeyMods = GetMergedKeyModFlags();
   4010     memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
   4011     for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
   4012         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;
   4013 
   4014     // Update gamepad/keyboard navigation
   4015     NavUpdate();
   4016 
   4017     // Update mouse input state
   4018     UpdateMouseInputs();
   4019 
   4020     // Find hovered window
   4021     // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
   4022     UpdateHoveredWindowAndCaptureFlags();
   4023 
   4024     // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
   4025     UpdateMouseMovingWindowNewFrame();
   4026 
   4027     // Background darkening/whitening
   4028     if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
   4029         g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
   4030     else
   4031         g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
   4032 
   4033     g.MouseCursor = ImGuiMouseCursor_Arrow;
   4034     g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
   4035     g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
   4036 
   4037     // Mouse wheel scrolling, scale
   4038     UpdateMouseWheel();
   4039 
   4040     // Update legacy TAB focus
   4041     UpdateTabFocus();
   4042 
   4043     // Mark all windows as not visible and compact unused memory.
   4044     IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
   4045     const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
   4046     for (int i = 0; i != g.Windows.Size; i++)
   4047     {
   4048         ImGuiWindow* window = g.Windows[i];
   4049         window->WasActive = window->Active;
   4050         window->BeginCount = 0;
   4051         window->Active = false;
   4052         window->WriteAccessed = false;
   4053 
   4054         // Garbage collect transient buffers of recently unused windows
   4055         if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
   4056             GcCompactTransientWindowBuffers(window);
   4057     }
   4058 
   4059     // Garbage collect transient buffers of recently unused tables
   4060     for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
   4061         if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
   4062             TableGcCompactTransientBuffers(g.Tables.GetByIndex(i));
   4063     for (int i = 0; i < g.TablesTempDataStack.Size; i++)
   4064         if (g.TablesTempDataStack[i].LastTimeActive >= 0.0f && g.TablesTempDataStack[i].LastTimeActive < memory_compact_start_time)
   4065             TableGcCompactTransientBuffers(&g.TablesTempDataStack[i]);
   4066     if (g.GcCompactAll)
   4067         GcCompactTransientMiscBuffers();
   4068     g.GcCompactAll = false;
   4069 
   4070     // Closing the focused window restore focus to the first active root window in descending z-order
   4071     if (g.NavWindow && !g.NavWindow->WasActive)
   4072         FocusTopMostWindowUnderOne(NULL, NULL);
   4073 
   4074     // No window should be open at the beginning of the frame.
   4075     // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
   4076     g.CurrentWindowStack.resize(0);
   4077     g.BeginPopupStack.resize(0);
   4078     g.ItemFlagsStack.resize(0);
   4079     g.ItemFlagsStack.push_back(ImGuiItemFlags_None);
   4080     g.GroupStack.resize(0);
   4081     ClosePopupsOverWindow(g.NavWindow, false);
   4082 
   4083     // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
   4084     UpdateDebugToolItemPicker();
   4085 
   4086     // Create implicit/fallback window - which we will only render it if the user has added something to it.
   4087     // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
   4088     // This fallback is particularly important as it avoid ImGui:: calls from crashing.
   4089     g.WithinFrameScopeWithImplicitWindow = true;
   4090     SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
   4091     Begin("Debug##Default");
   4092     IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true);
   4093 
   4094     CallContextHooks(&g, ImGuiContextHookType_NewFramePost);
   4095 }
   4096 
   4097 // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
   4098 void ImGui::UpdateDebugToolItemPicker()
   4099 {
   4100     ImGuiContext& g = *GImGui;
   4101     g.DebugItemPickerBreakId = 0;
   4102     if (g.DebugItemPickerActive)
   4103     {
   4104         const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
   4105         SetMouseCursor(ImGuiMouseCursor_Hand);
   4106         if (IsKeyPressedMap(ImGuiKey_Escape))
   4107             g.DebugItemPickerActive = false;
   4108         if (IsMouseClicked(0) && hovered_id)
   4109         {
   4110             g.DebugItemPickerBreakId = hovered_id;
   4111             g.DebugItemPickerActive = false;
   4112         }
   4113         SetNextWindowBgAlpha(0.60f);
   4114         BeginTooltip();
   4115         Text("HoveredId: 0x%08X", hovered_id);
   4116         Text("Press ESC to abort picking.");
   4117         TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
   4118         EndTooltip();
   4119     }
   4120 }
   4121 
   4122 void ImGui::Initialize(ImGuiContext* context)
   4123 {
   4124     ImGuiContext& g = *context;
   4125     IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
   4126 
   4127     // Add .ini handle for ImGuiWindow type
   4128     {
   4129         ImGuiSettingsHandler ini_handler;
   4130         ini_handler.TypeName = "Window";
   4131         ini_handler.TypeHash = ImHashStr("Window");
   4132         ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;
   4133         ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
   4134         ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
   4135         ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
   4136         ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
   4137         g.SettingsHandlers.push_back(ini_handler);
   4138     }
   4139 
   4140     // Add .ini handle for ImGuiTable type
   4141     TableSettingsInstallHandler(context);
   4142 
   4143     // Create default viewport
   4144     ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
   4145     g.Viewports.push_back(viewport);
   4146 
   4147 #ifdef IMGUI_HAS_DOCK
   4148 #endif // #ifdef IMGUI_HAS_DOCK
   4149 
   4150     g.Initialized = true;
   4151 }
   4152 
   4153 // This function is merely here to free heap allocations.
   4154 void ImGui::Shutdown(ImGuiContext* context)
   4155 {
   4156     // 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)
   4157     ImGuiContext& g = *context;
   4158     if (g.IO.Fonts && g.FontAtlasOwnedByContext)
   4159     {
   4160         g.IO.Fonts->Locked = false;
   4161         IM_DELETE(g.IO.Fonts);
   4162     }
   4163     g.IO.Fonts = NULL;
   4164 
   4165     // Cleanup of other data are conditional on actually having initialized Dear ImGui.
   4166     if (!g.Initialized)
   4167         return;
   4168 
   4169     // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
   4170     if (g.SettingsLoaded && g.IO.IniFilename != NULL)
   4171     {
   4172         ImGuiContext* backup_context = GImGui;
   4173         SetCurrentContext(&g);
   4174         SaveIniSettingsToDisk(g.IO.IniFilename);
   4175         SetCurrentContext(backup_context);
   4176     }
   4177 
   4178     CallContextHooks(&g, ImGuiContextHookType_Shutdown);
   4179 
   4180     // Clear everything else
   4181     for (int i = 0; i < g.Windows.Size; i++)
   4182         IM_DELETE(g.Windows[i]);
   4183     g.Windows.clear();
   4184     g.WindowsFocusOrder.clear();
   4185     g.WindowsTempSortBuffer.clear();
   4186     g.CurrentWindow = NULL;
   4187     g.CurrentWindowStack.clear();
   4188     g.WindowsById.Clear();
   4189     g.NavWindow = NULL;
   4190     g.HoveredWindow = g.HoveredWindowUnderMovingWindow = NULL;
   4191     g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;
   4192     g.MovingWindow = NULL;
   4193     g.ColorStack.clear();
   4194     g.StyleVarStack.clear();
   4195     g.FontStack.clear();
   4196     g.OpenPopupStack.clear();
   4197     g.BeginPopupStack.clear();
   4198 
   4199     for (int i = 0; i < g.Viewports.Size; i++)
   4200         IM_DELETE(g.Viewports[i]);
   4201     g.Viewports.clear();
   4202 
   4203     g.TabBars.Clear();
   4204     g.CurrentTabBarStack.clear();
   4205     g.ShrinkWidthBuffer.clear();
   4206 
   4207     g.Tables.Clear();
   4208     for (int i = 0; i < g.TablesTempDataStack.Size; i++)
   4209         g.TablesTempDataStack[i].~ImGuiTableTempData();
   4210     g.TablesTempDataStack.clear();
   4211     g.DrawChannelsTempMergeBuffer.clear();
   4212 
   4213     g.ClipboardHandlerData.clear();
   4214     g.MenusIdSubmittedThisFrame.clear();
   4215     g.InputTextState.ClearFreeMemory();
   4216 
   4217     g.SettingsWindows.clear();
   4218     g.SettingsHandlers.clear();
   4219 
   4220     if (g.LogFile)
   4221     {
   4222 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS
   4223         if (g.LogFile != stdout)
   4224 #endif
   4225             ImFileClose(g.LogFile);
   4226         g.LogFile = NULL;
   4227     }
   4228     g.LogBuffer.clear();
   4229 
   4230     g.Initialized = false;
   4231 }
   4232 
   4233 // FIXME: Add a more explicit sort order in the window structure.
   4234 static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
   4235 {
   4236     const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
   4237     const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
   4238     if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
   4239         return d;
   4240     if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
   4241         return d;
   4242     return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
   4243 }
   4244 
   4245 static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
   4246 {
   4247     out_sorted_windows->push_back(window);
   4248     if (window->Active)
   4249     {
   4250         int count = window->DC.ChildWindows.Size;
   4251         if (count > 1)
   4252             ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
   4253         for (int i = 0; i < count; i++)
   4254         {
   4255             ImGuiWindow* child = window->DC.ChildWindows[i];
   4256             if (child->Active)
   4257                 AddWindowToSortBuffer(out_sorted_windows, child);
   4258         }
   4259     }
   4260 }
   4261 
   4262 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
   4263 {
   4264     // Remove trailing command if unused.
   4265     // Technically we could return directly instead of popping, but this make things looks neat in Metrics/Debugger window as well.
   4266     draw_list->_PopUnusedDrawCmd();
   4267     if (draw_list->CmdBuffer.Size == 0)
   4268         return;
   4269 
   4270     // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
   4271     // May trigger for you if you are using PrimXXX functions incorrectly.
   4272     IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
   4273     IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
   4274     if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
   4275         IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
   4276 
   4277     // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
   4278     // If this assert triggers because you are drawing lots of stuff manually:
   4279     // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
   4280     //   Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics/Debugger window to inspect draw list contents.
   4281     // - If you want large meshes with more than 64K vertices, you can either:
   4282     //   (A) Handle the ImDrawCmd::VtxOffset value in your renderer backend, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
   4283     //       Most example backends already support this from 1.71. Pre-1.71 backends won't.
   4284     //       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.
   4285     //   (B) Or handle 32-bit indices in your renderer backend, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
   4286     //       Most example backends already support this. For example, the OpenGL example code detect index size at compile-time:
   4287     //         glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
   4288     //       Your own engine or render API may use different parameters or function calls to specify index sizes.
   4289     //       2 and 4 bytes indices are generally supported by most graphics API.
   4290     // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
   4291     //   the 64K limit to split your draw commands in multiple draw lists.
   4292     if (sizeof(ImDrawIdx) == 2)
   4293         IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
   4294 
   4295     out_list->push_back(draw_list);
   4296 }
   4297 
   4298 static void AddWindowToDrawData(ImGuiWindow* window, int layer)
   4299 {
   4300     ImGuiContext& g = *GImGui;
   4301     ImGuiViewportP* viewport = g.Viewports[0];
   4302     g.IO.MetricsRenderWindows++;
   4303     AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[layer], window->DrawList);
   4304     for (int i = 0; i < window->DC.ChildWindows.Size; i++)
   4305     {
   4306         ImGuiWindow* child = window->DC.ChildWindows[i];
   4307         if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active
   4308             AddWindowToDrawData(child, layer);
   4309     }
   4310 }
   4311 
   4312 // Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu)
   4313 static void AddRootWindowToDrawData(ImGuiWindow* window)
   4314 {
   4315     int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;
   4316     AddWindowToDrawData(window, layer);
   4317 }
   4318 
   4319 void ImDrawDataBuilder::FlattenIntoSingleLayer()
   4320 {
   4321     int n = Layers[0].Size;
   4322     int size = n;
   4323     for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
   4324         size += Layers[i].Size;
   4325     Layers[0].resize(size);
   4326     for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
   4327     {
   4328         ImVector<ImDrawList*>& layer = Layers[layer_n];
   4329         if (layer.empty())
   4330             continue;
   4331         memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
   4332         n += layer.Size;
   4333         layer.resize(0);
   4334     }
   4335 }
   4336 
   4337 static void SetupViewportDrawData(ImGuiViewportP* viewport, ImVector<ImDrawList*>* draw_lists)
   4338 {
   4339     ImGuiIO& io = ImGui::GetIO();
   4340     ImDrawData* draw_data = &viewport->DrawDataP;
   4341     draw_data->Valid = true;
   4342     draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
   4343     draw_data->CmdListsCount = draw_lists->Size;
   4344     draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
   4345     draw_data->DisplayPos = viewport->Pos;
   4346     draw_data->DisplaySize = viewport->Size;
   4347     draw_data->FramebufferScale = io.DisplayFramebufferScale;
   4348     for (int n = 0; n < draw_lists->Size; n++)
   4349     {
   4350         draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
   4351         draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
   4352     }
   4353 }
   4354 
   4355 // Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering.
   4356 // - When using this function it is sane to ensure that float are perfectly rounded to integer values,
   4357 //   so that e.g. (int)(max.x-min.x) in user's render produce correct result.
   4358 // - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect():
   4359 //   some frequently called functions which to modify both channels and clipping simultaneously tend to use the
   4360 //   more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds.
   4361 void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
   4362 {
   4363     ImGuiWindow* window = GetCurrentWindow();
   4364     window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
   4365     window->ClipRect = window->DrawList->_ClipRectStack.back();
   4366 }
   4367 
   4368 void ImGui::PopClipRect()
   4369 {
   4370     ImGuiWindow* window = GetCurrentWindow();
   4371     window->DrawList->PopClipRect();
   4372     window->ClipRect = window->DrawList->_ClipRectStack.back();
   4373 }
   4374 
   4375 // 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.
   4376 void ImGui::EndFrame()
   4377 {
   4378     ImGuiContext& g = *GImGui;
   4379     IM_ASSERT(g.Initialized);
   4380 
   4381     // Don't process EndFrame() multiple times.
   4382     if (g.FrameCountEnded == g.FrameCount)
   4383         return;
   4384     IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
   4385 
   4386     CallContextHooks(&g, ImGuiContextHookType_EndFramePre);
   4387 
   4388     ErrorCheckEndFrameSanityChecks();
   4389 
   4390     // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
   4391     if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f))
   4392     {
   4393         g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y);
   4394         g.PlatformImeLastPos = g.PlatformImePos;
   4395     }
   4396 
   4397     // Hide implicit/fallback "Debug" window if it hasn't been used
   4398     g.WithinFrameScopeWithImplicitWindow = false;
   4399     if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
   4400         g.CurrentWindow->Active = false;
   4401     End();
   4402 
   4403     // Update navigation: CTRL+Tab, wrap-around requests
   4404     NavEndFrame();
   4405 
   4406     // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
   4407     if (g.DragDropActive)
   4408     {
   4409         bool is_delivered = g.DragDropPayload.Delivery;
   4410         bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));
   4411         if (is_delivered || is_elapsed)
   4412             ClearDragDrop();
   4413     }
   4414 
   4415     // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.
   4416     if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
   4417     {
   4418         g.DragDropWithinSource = true;
   4419         SetTooltip("...");
   4420         g.DragDropWithinSource = false;
   4421     }
   4422 
   4423     // End frame
   4424     g.WithinFrameScope = false;
   4425     g.FrameCountEnded = g.FrameCount;
   4426 
   4427     // Initiate moving window + handle left-click and right-click focus
   4428     UpdateMouseMovingWindowEndFrame();
   4429 
   4430     // Sort the window list so that all child windows are after their parent
   4431     // We cannot do that on FocusWindow() because children may not exist yet
   4432     g.WindowsTempSortBuffer.resize(0);
   4433     g.WindowsTempSortBuffer.reserve(g.Windows.Size);
   4434     for (int i = 0; i != g.Windows.Size; i++)
   4435     {
   4436         ImGuiWindow* window = g.Windows[i];
   4437         if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow))       // if a child is active its parent will add it
   4438             continue;
   4439         AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);
   4440     }
   4441 
   4442     // 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.
   4443     IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size);
   4444     g.Windows.swap(g.WindowsTempSortBuffer);
   4445     g.IO.MetricsActiveWindows = g.WindowsActiveCount;
   4446 
   4447     // Unlock font atlas
   4448     g.IO.Fonts->Locked = false;
   4449 
   4450     // Clear Input data for next frame
   4451     g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
   4452     g.IO.InputQueueCharacters.resize(0);
   4453     memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
   4454 
   4455     CallContextHooks(&g, ImGuiContextHookType_EndFramePost);
   4456 }
   4457 
   4458 void ImGui::Render()
   4459 {
   4460     ImGuiContext& g = *GImGui;
   4461     IM_ASSERT(g.Initialized);
   4462 
   4463     if (g.FrameCountEnded != g.FrameCount)
   4464         EndFrame();
   4465     g.FrameCountRendered = g.FrameCount;
   4466     g.IO.MetricsRenderWindows = 0;
   4467 
   4468     CallContextHooks(&g, ImGuiContextHookType_RenderPre);
   4469 
   4470     // Add background ImDrawList (for each active viewport)
   4471     for (int n = 0; n != g.Viewports.Size; n++)
   4472     {
   4473         ImGuiViewportP* viewport = g.Viewports[n];
   4474         viewport->DrawDataBuilder.Clear();
   4475         if (viewport->DrawLists[0] != NULL)
   4476             AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport));
   4477     }
   4478 
   4479     // Add ImDrawList to render
   4480     ImGuiWindow* windows_to_render_top_most[2];
   4481     windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
   4482     windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);
   4483     for (int n = 0; n != g.Windows.Size; n++)
   4484     {
   4485         ImGuiWindow* window = g.Windows[n];
   4486         IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
   4487         if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
   4488             AddRootWindowToDrawData(window);
   4489     }
   4490     for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
   4491         if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
   4492             AddRootWindowToDrawData(windows_to_render_top_most[n]);
   4493 
   4494     // Setup ImDrawData structures for end-user
   4495     g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0;
   4496     for (int n = 0; n < g.Viewports.Size; n++)
   4497     {
   4498         ImGuiViewportP* viewport = g.Viewports[n];
   4499         viewport->DrawDataBuilder.FlattenIntoSingleLayer();
   4500 
   4501         // Draw software mouse cursor if requested by io.MouseDrawCursor flag
   4502         if (g.IO.MouseDrawCursor)
   4503             RenderMouseCursor(GetForegroundDrawList(viewport), g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
   4504 
   4505         // Add foreground ImDrawList (for each active viewport)
   4506         if (viewport->DrawLists[1] != NULL)
   4507             AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport));
   4508 
   4509         SetupViewportDrawData(viewport, &viewport->DrawDataBuilder.Layers[0]);
   4510         ImDrawData* draw_data = &viewport->DrawDataP;
   4511         g.IO.MetricsRenderVertices += draw_data->TotalVtxCount;
   4512         g.IO.MetricsRenderIndices += draw_data->TotalIdxCount;
   4513     }
   4514 
   4515     CallContextHooks(&g, ImGuiContextHookType_RenderPost);
   4516 }
   4517 
   4518 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
   4519 // CalcTextSize("") should return ImVec2(0.0f, g.FontSize)
   4520 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
   4521 {
   4522     ImGuiContext& g = *GImGui;
   4523 
   4524     const char* text_display_end;
   4525     if (hide_text_after_double_hash)
   4526         text_display_end = FindRenderedTextEnd(text, text_end);      // Hide anything after a '##' string
   4527     else
   4528         text_display_end = text_end;
   4529 
   4530     ImFont* font = g.Font;
   4531     const float font_size = g.FontSize;
   4532     if (text == text_display_end)
   4533         return ImVec2(0.0f, font_size);
   4534     ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
   4535 
   4536     // Round
   4537     // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out.
   4538     // FIXME: Investigate using ceilf or e.g.
   4539     // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c
   4540     // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html
   4541     text_size.x = IM_FLOOR(text_size.x + 0.99999f);
   4542 
   4543     return text_size;
   4544 }
   4545 
   4546 // Find window given position, search front-to-back
   4547 // FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically
   4548 // with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
   4549 // called, aka before the next Begin(). Moving window isn't affected.
   4550 static void FindHoveredWindow()
   4551 {
   4552     ImGuiContext& g = *GImGui;
   4553 
   4554     ImGuiWindow* hovered_window = NULL;
   4555     ImGuiWindow* hovered_window_ignoring_moving_window = NULL;
   4556     if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs))
   4557         hovered_window = g.MovingWindow;
   4558 
   4559     ImVec2 padding_regular = g.Style.TouchExtraPadding;
   4560     ImVec2 padding_for_resize = g.IO.ConfigWindowsResizeFromEdges ? g.WindowsHoverPadding : padding_regular;
   4561     for (int i = g.Windows.Size - 1; i >= 0; i--)
   4562     {
   4563         ImGuiWindow* window = g.Windows[i];
   4564         IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
   4565         if (!window->Active || window->Hidden)
   4566             continue;
   4567         if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
   4568             continue;
   4569 
   4570         // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
   4571         ImRect bb(window->OuterRectClipped);
   4572         if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
   4573             bb.Expand(padding_regular);
   4574         else
   4575             bb.Expand(padding_for_resize);
   4576         if (!bb.Contains(g.IO.MousePos))
   4577             continue;
   4578 
   4579         // Support for one rectangular hole in any given window
   4580         // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512)
   4581         if (window->HitTestHoleSize.x != 0)
   4582         {
   4583             ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y);
   4584             ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y);
   4585             if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos))
   4586                 continue;
   4587         }
   4588 
   4589         if (hovered_window == NULL)
   4590             hovered_window = window;
   4591         IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
   4592         if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))
   4593             hovered_window_ignoring_moving_window = window;
   4594         if (hovered_window && hovered_window_ignoring_moving_window)
   4595             break;
   4596     }
   4597 
   4598     g.HoveredWindow = hovered_window;
   4599     g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;
   4600 }
   4601 
   4602 // Test if mouse cursor is hovering given rectangle
   4603 // NB- Rectangle is clipped by our current clip setting
   4604 // NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
   4605 bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
   4606 {
   4607     ImGuiContext& g = *GImGui;
   4608 
   4609     // Clip
   4610     ImRect rect_clipped(r_min, r_max);
   4611     if (clip)
   4612         rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
   4613 
   4614     // Expand for touch input
   4615     const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
   4616     if (!rect_for_touch.Contains(g.IO.MousePos))
   4617         return false;
   4618     return true;
   4619 }
   4620 
   4621 int ImGui::GetKeyIndex(ImGuiKey imgui_key)
   4622 {
   4623     IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
   4624     ImGuiContext& g = *GImGui;
   4625     return g.IO.KeyMap[imgui_key];
   4626 }
   4627 
   4628 // Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]!
   4629 // Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]!
   4630 bool ImGui::IsKeyDown(int user_key_index)
   4631 {
   4632     if (user_key_index < 0)
   4633         return false;
   4634     ImGuiContext& g = *GImGui;
   4635     IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
   4636     return g.IO.KeysDown[user_key_index];
   4637 }
   4638 
   4639 // t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
   4640 // t1 = current time (e.g.: g.Time)
   4641 // An event is triggered at:
   4642 //  t = 0.0f     t = repeat_delay,    t = repeat_delay + repeat_rate*N
   4643 int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
   4644 {
   4645     if (t1 == 0.0f)
   4646         return 1;
   4647     if (t0 >= t1)
   4648         return 0;
   4649     if (repeat_rate <= 0.0f)
   4650         return (t0 < repeat_delay) && (t1 >= repeat_delay);
   4651     const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
   4652     const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
   4653     const int count = count_t1 - count_t0;
   4654     return count;
   4655 }
   4656 
   4657 int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
   4658 {
   4659     ImGuiContext& g = *GImGui;
   4660     if (key_index < 0)
   4661         return 0;
   4662     IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
   4663     const float t = g.IO.KeysDownDuration[key_index];
   4664     return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
   4665 }
   4666 
   4667 bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
   4668 {
   4669     ImGuiContext& g = *GImGui;
   4670     if (user_key_index < 0)
   4671         return false;
   4672     IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
   4673     const float t = g.IO.KeysDownDuration[user_key_index];
   4674     if (t == 0.0f)
   4675         return true;
   4676     if (repeat && t > g.IO.KeyRepeatDelay)
   4677         return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
   4678     return false;
   4679 }
   4680 
   4681 bool ImGui::IsKeyReleased(int user_key_index)
   4682 {
   4683     ImGuiContext& g = *GImGui;
   4684     if (user_key_index < 0) return false;
   4685     IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
   4686     return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
   4687 }
   4688 
   4689 bool ImGui::IsMouseDown(ImGuiMouseButton button)
   4690 {
   4691     ImGuiContext& g = *GImGui;
   4692     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4693     return g.IO.MouseDown[button];
   4694 }
   4695 
   4696 bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
   4697 {
   4698     ImGuiContext& g = *GImGui;
   4699     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4700     const float t = g.IO.MouseDownDuration[button];
   4701     if (t == 0.0f)
   4702         return true;
   4703 
   4704     if (repeat && t > g.IO.KeyRepeatDelay)
   4705     {
   4706         // 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.
   4707         int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f);
   4708         if (amount > 0)
   4709             return true;
   4710     }
   4711     return false;
   4712 }
   4713 
   4714 bool ImGui::IsMouseReleased(ImGuiMouseButton button)
   4715 {
   4716     ImGuiContext& g = *GImGui;
   4717     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4718     return g.IO.MouseReleased[button];
   4719 }
   4720 
   4721 bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
   4722 {
   4723     ImGuiContext& g = *GImGui;
   4724     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4725     return g.IO.MouseDoubleClicked[button];
   4726 }
   4727 
   4728 // Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
   4729 // [Internal] This doesn't test if the button is pressed
   4730 bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold)
   4731 {
   4732     ImGuiContext& g = *GImGui;
   4733     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4734     if (lock_threshold < 0.0f)
   4735         lock_threshold = g.IO.MouseDragThreshold;
   4736     return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
   4737 }
   4738 
   4739 bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
   4740 {
   4741     ImGuiContext& g = *GImGui;
   4742     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4743     if (!g.IO.MouseDown[button])
   4744         return false;
   4745     return IsMouseDragPastThreshold(button, lock_threshold);
   4746 }
   4747 
   4748 ImVec2 ImGui::GetMousePos()
   4749 {
   4750     ImGuiContext& g = *GImGui;
   4751     return g.IO.MousePos;
   4752 }
   4753 
   4754 // NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
   4755 ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
   4756 {
   4757     ImGuiContext& g = *GImGui;
   4758     if (g.BeginPopupStack.Size > 0)
   4759         return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;
   4760     return g.IO.MousePos;
   4761 }
   4762 
   4763 // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
   4764 bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
   4765 {
   4766     // The assert is only to silence a false-positive in XCode Static Analysis.
   4767     // 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).
   4768     IM_ASSERT(GImGui != NULL);
   4769     const float MOUSE_INVALID = -256000.0f;
   4770     ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
   4771     return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
   4772 }
   4773 
   4774 bool ImGui::IsAnyMouseDown()
   4775 {
   4776     ImGuiContext& g = *GImGui;
   4777     for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
   4778         if (g.IO.MouseDown[n])
   4779             return true;
   4780     return false;
   4781 }
   4782 
   4783 // Return the delta from the initial clicking position while the mouse button is clicked or was just released.
   4784 // This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
   4785 // NB: This is only valid if IsMousePosValid(). backends in theory should always keep mouse position valid when dragging even outside the client window.
   4786 ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold)
   4787 {
   4788     ImGuiContext& g = *GImGui;
   4789     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4790     if (lock_threshold < 0.0f)
   4791         lock_threshold = g.IO.MouseDragThreshold;
   4792     if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
   4793         if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
   4794             if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button]))
   4795                 return g.IO.MousePos - g.IO.MouseClickedPos[button];
   4796     return ImVec2(0.0f, 0.0f);
   4797 }
   4798 
   4799 void ImGui::ResetMouseDragDelta(ImGuiMouseButton button)
   4800 {
   4801     ImGuiContext& g = *GImGui;
   4802     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
   4803     // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
   4804     g.IO.MouseClickedPos[button] = g.IO.MousePos;
   4805 }
   4806 
   4807 ImGuiMouseCursor ImGui::GetMouseCursor()
   4808 {
   4809     return GImGui->MouseCursor;
   4810 }
   4811 
   4812 void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
   4813 {
   4814     GImGui->MouseCursor = cursor_type;
   4815 }
   4816 
   4817 void ImGui::CaptureKeyboardFromApp(bool capture)
   4818 {
   4819     GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
   4820 }
   4821 
   4822 void ImGui::CaptureMouseFromApp(bool capture)
   4823 {
   4824     GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
   4825 }
   4826 
   4827 bool ImGui::IsItemActive()
   4828 {
   4829     ImGuiContext& g = *GImGui;
   4830     if (g.ActiveId)
   4831     {
   4832         ImGuiWindow* window = g.CurrentWindow;
   4833         return g.ActiveId == window->DC.LastItemId;
   4834     }
   4835     return false;
   4836 }
   4837 
   4838 bool ImGui::IsItemActivated()
   4839 {
   4840     ImGuiContext& g = *GImGui;
   4841     if (g.ActiveId)
   4842     {
   4843         ImGuiWindow* window = g.CurrentWindow;
   4844         if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
   4845             return true;
   4846     }
   4847     return false;
   4848 }
   4849 
   4850 bool ImGui::IsItemDeactivated()
   4851 {
   4852     ImGuiContext& g = *GImGui;
   4853     ImGuiWindow* window = g.CurrentWindow;
   4854     if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
   4855         return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
   4856     return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
   4857 }
   4858 
   4859 bool ImGui::IsItemDeactivatedAfterEdit()
   4860 {
   4861     ImGuiContext& g = *GImGui;
   4862     return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));
   4863 }
   4864 
   4865 // == GetItemID() == GetFocusID()
   4866 bool ImGui::IsItemFocused()
   4867 {
   4868     ImGuiContext& g = *GImGui;
   4869     ImGuiWindow* window = g.CurrentWindow;
   4870 
   4871     if (g.NavId != window->DC.LastItemId || g.NavId == 0)
   4872         return false;
   4873     return true;
   4874 }
   4875 
   4876 // Important: this can be useful but it is NOT equivalent to the behavior of e.g.Button()!
   4877 // Most widgets have specific reactions based on mouse-up/down state, mouse position etc.
   4878 bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)
   4879 {
   4880     return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
   4881 }
   4882 
   4883 bool ImGui::IsItemToggledOpen()
   4884 {
   4885     ImGuiContext& g = *GImGui;
   4886     return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
   4887 }
   4888 
   4889 bool ImGui::IsItemToggledSelection()
   4890 {
   4891     ImGuiContext& g = *GImGui;
   4892     return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
   4893 }
   4894 
   4895 bool ImGui::IsAnyItemHovered()
   4896 {
   4897     ImGuiContext& g = *GImGui;
   4898     return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
   4899 }
   4900 
   4901 bool ImGui::IsAnyItemActive()
   4902 {
   4903     ImGuiContext& g = *GImGui;
   4904     return g.ActiveId != 0;
   4905 }
   4906 
   4907 bool ImGui::IsAnyItemFocused()
   4908 {
   4909     ImGuiContext& g = *GImGui;
   4910     return g.NavId != 0 && !g.NavDisableHighlight;
   4911 }
   4912 
   4913 bool ImGui::IsItemVisible()
   4914 {
   4915     ImGuiWindow* window = GetCurrentWindowRead();
   4916     return window->ClipRect.Overlaps(window->DC.LastItemRect);
   4917 }
   4918 
   4919 bool ImGui::IsItemEdited()
   4920 {
   4921     ImGuiWindow* window = GetCurrentWindowRead();
   4922     return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0;
   4923 }
   4924 
   4925 // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
   4926 // FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowItemOverlap flag are extremely confusing, need rework.
   4927 void ImGui::SetItemAllowOverlap()
   4928 {
   4929     ImGuiContext& g = *GImGui;
   4930     ImGuiID id = g.CurrentWindow->DC.LastItemId;
   4931     if (g.HoveredId == id)
   4932         g.HoveredIdAllowOverlap = true;
   4933     if (g.ActiveId == id)
   4934         g.ActiveIdAllowOverlap = true;
   4935 }
   4936 
   4937 void ImGui::SetItemUsingMouseWheel()
   4938 {
   4939     ImGuiContext& g = *GImGui;
   4940     ImGuiID id = g.CurrentWindow->DC.LastItemId;
   4941     if (g.HoveredId == id)
   4942         g.HoveredIdUsingMouseWheel = true;
   4943     if (g.ActiveId == id)
   4944         g.ActiveIdUsingMouseWheel = true;
   4945 }
   4946 
   4947 ImVec2 ImGui::GetItemRectMin()
   4948 {
   4949     ImGuiWindow* window = GetCurrentWindowRead();
   4950     return window->DC.LastItemRect.Min;
   4951 }
   4952 
   4953 ImVec2 ImGui::GetItemRectMax()
   4954 {
   4955     ImGuiWindow* window = GetCurrentWindowRead();
   4956     return window->DC.LastItemRect.Max;
   4957 }
   4958 
   4959 ImVec2 ImGui::GetItemRectSize()
   4960 {
   4961     ImGuiWindow* window = GetCurrentWindowRead();
   4962     return window->DC.LastItemRect.GetSize();
   4963 }
   4964 
   4965 bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
   4966 {
   4967     ImGuiContext& g = *GImGui;
   4968     ImGuiWindow* parent_window = g.CurrentWindow;
   4969 
   4970     flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow;
   4971     flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove);  // Inherit the NoMove flag
   4972 
   4973     // Size
   4974     const ImVec2 content_avail = GetContentRegionAvail();
   4975     ImVec2 size = ImFloor(size_arg);
   4976     const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
   4977     if (size.x <= 0.0f)
   4978         size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
   4979     if (size.y <= 0.0f)
   4980         size.y = ImMax(content_avail.y + size.y, 4.0f);
   4981     SetNextWindowSize(size);
   4982 
   4983     // 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.
   4984     if (name)
   4985         ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%s_%08X", parent_window->Name, name, id);
   4986     else
   4987         ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%08X", parent_window->Name, id);
   4988 
   4989     const float backup_border_size = g.Style.ChildBorderSize;
   4990     if (!border)
   4991         g.Style.ChildBorderSize = 0.0f;
   4992     bool ret = Begin(g.TempBuffer, NULL, flags);
   4993     g.Style.ChildBorderSize = backup_border_size;
   4994 
   4995     ImGuiWindow* child_window = g.CurrentWindow;
   4996     child_window->ChildId = id;
   4997     child_window->AutoFitChildAxises = (ImS8)auto_fit_axises;
   4998 
   4999     // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
   5000     // While this is not really documented/defined, it seems that the expected thing to do.
   5001     if (child_window->BeginCount == 1)
   5002         parent_window->DC.CursorPos = child_window->Pos;
   5003 
   5004     // Process navigation-in immediately so NavInit can run on first frame
   5005     if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavHasScroll))
   5006     {
   5007         FocusWindow(child_window);
   5008         NavInitWindow(child_window, false);
   5009         SetActiveID(id + 1, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item
   5010         g.ActiveIdSource = ImGuiInputSource_Nav;
   5011     }
   5012     return ret;
   5013 }
   5014 
   5015 bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
   5016 {
   5017     ImGuiWindow* window = GetCurrentWindow();
   5018     return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
   5019 }
   5020 
   5021 bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
   5022 {
   5023     IM_ASSERT(id != 0);
   5024     return BeginChildEx(NULL, id, size_arg, border, extra_flags);
   5025 }
   5026 
   5027 void ImGui::EndChild()
   5028 {
   5029     ImGuiContext& g = *GImGui;
   5030     ImGuiWindow* window = g.CurrentWindow;
   5031 
   5032     IM_ASSERT(g.WithinEndChild == false);
   5033     IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);   // Mismatched BeginChild()/EndChild() calls
   5034 
   5035     g.WithinEndChild = true;
   5036     if (window->BeginCount > 1)
   5037     {
   5038         End();
   5039     }
   5040     else
   5041     {
   5042         ImVec2 sz = window->Size;
   5043         if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
   5044             sz.x = ImMax(4.0f, sz.x);
   5045         if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
   5046             sz.y = ImMax(4.0f, sz.y);
   5047         End();
   5048 
   5049         ImGuiWindow* parent_window = g.CurrentWindow;
   5050         ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
   5051         ItemSize(sz);
   5052         if ((window->DC.NavLayersActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
   5053         {
   5054             ItemAdd(bb, window->ChildId);
   5055             RenderNavHighlight(bb, window->ChildId);
   5056 
   5057             // When browsing a window that has no activable items (scroll only) we keep a highlight on the child
   5058             if (window->DC.NavLayersActiveMask == 0 && window == g.NavWindow)
   5059                 RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
   5060         }
   5061         else
   5062         {
   5063             // Not navigable into
   5064             ItemAdd(bb, 0);
   5065         }
   5066         if (g.HoveredWindow == window)
   5067             parent_window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
   5068     }
   5069     g.WithinEndChild = false;
   5070     g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
   5071 }
   5072 
   5073 // Helper to create a child window / scrolling region that looks like a normal widget frame.
   5074 bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)
   5075 {
   5076     ImGuiContext& g = *GImGui;
   5077     const ImGuiStyle& style = g.Style;
   5078     PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
   5079     PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
   5080     PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
   5081     PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
   5082     bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);
   5083     PopStyleVar(3);
   5084     PopStyleColor();
   5085     return ret;
   5086 }
   5087 
   5088 void ImGui::EndChildFrame()
   5089 {
   5090     EndChild();
   5091 }
   5092 
   5093 static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
   5094 {
   5095     window->SetWindowPosAllowFlags       = enabled ? (window->SetWindowPosAllowFlags       | flags) : (window->SetWindowPosAllowFlags       & ~flags);
   5096     window->SetWindowSizeAllowFlags      = enabled ? (window->SetWindowSizeAllowFlags      | flags) : (window->SetWindowSizeAllowFlags      & ~flags);
   5097     window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
   5098 }
   5099 
   5100 ImGuiWindow* ImGui::FindWindowByID(ImGuiID id)
   5101 {
   5102     ImGuiContext& g = *GImGui;
   5103     return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
   5104 }
   5105 
   5106 ImGuiWindow* ImGui::FindWindowByName(const char* name)
   5107 {
   5108     ImGuiID id = ImHashStr(name);
   5109     return FindWindowByID(id);
   5110 }
   5111 
   5112 static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)
   5113 {
   5114     window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y));
   5115     if (settings->Size.x > 0 && settings->Size.y > 0)
   5116         window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y));
   5117     window->Collapsed = settings->Collapsed;
   5118 }
   5119 
   5120 static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
   5121 {
   5122     ImGuiContext& g = *GImGui;
   5123     //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
   5124 
   5125     // Create window the first time
   5126     ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
   5127     window->Flags = flags;
   5128     g.WindowsById.SetVoidPtr(window->ID, window);
   5129 
   5130     // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
   5131     const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
   5132     window->Pos = main_viewport->Pos + ImVec2(60, 60);
   5133 
   5134     // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
   5135     if (!(flags & ImGuiWindowFlags_NoSavedSettings))
   5136         if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
   5137         {
   5138             // Retrieve settings from .ini file
   5139             window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
   5140             SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
   5141             ApplyWindowSettings(window, settings);
   5142         }
   5143     window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
   5144 
   5145     if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
   5146     {
   5147         window->AutoFitFramesX = window->AutoFitFramesY = 2;
   5148         window->AutoFitOnlyGrows = false;
   5149     }
   5150     else
   5151     {
   5152         if (window->Size.x <= 0.0f)
   5153             window->AutoFitFramesX = 2;
   5154         if (window->Size.y <= 0.0f)
   5155             window->AutoFitFramesY = 2;
   5156         window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
   5157     }
   5158 
   5159     if (!(flags & ImGuiWindowFlags_ChildWindow))
   5160     {
   5161         g.WindowsFocusOrder.push_back(window);
   5162         window->FocusOrder = (short)(g.WindowsFocusOrder.Size - 1);
   5163     }
   5164 
   5165     if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
   5166         g.Windows.push_front(window); // Quite slow but rare and only once
   5167     else
   5168         g.Windows.push_back(window);
   5169     return window;
   5170 }
   5171 
   5172 static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, const ImVec2& size_desired)
   5173 {
   5174     ImGuiContext& g = *GImGui;
   5175     ImVec2 new_size = size_desired;
   5176     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
   5177     {
   5178         // Using -1,-1 on either X/Y axis to preserve the current size.
   5179         ImRect cr = g.NextWindowData.SizeConstraintRect;
   5180         new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
   5181         new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
   5182         if (g.NextWindowData.SizeCallback)
   5183         {
   5184             ImGuiSizeCallbackData data;
   5185             data.UserData = g.NextWindowData.SizeCallbackUserData;
   5186             data.Pos = window->Pos;
   5187             data.CurrentSize = window->SizeFull;
   5188             data.DesiredSize = new_size;
   5189             g.NextWindowData.SizeCallback(&data);
   5190             new_size = data.DesiredSize;
   5191         }
   5192         new_size.x = IM_FLOOR(new_size.x);
   5193         new_size.y = IM_FLOOR(new_size.y);
   5194     }
   5195 
   5196     // Minimum size
   5197     if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
   5198     {
   5199         ImGuiWindow* window_for_height = window;
   5200         const float decoration_up_height = window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight();
   5201         new_size = ImMax(new_size, g.Style.WindowMinSize);
   5202         new_size.y = ImMax(new_size.y, decoration_up_height + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
   5203     }
   5204     return new_size;
   5205 }
   5206 
   5207 static void CalcWindowContentSizes(ImGuiWindow* window, ImVec2* content_size_current, ImVec2* content_size_ideal)
   5208 {
   5209     bool preserve_old_content_sizes = false;
   5210     if (window->Collapsed && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
   5211         preserve_old_content_sizes = true;
   5212     else if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
   5213         preserve_old_content_sizes = true;
   5214     if (preserve_old_content_sizes)
   5215     {
   5216         *content_size_current = window->ContentSize;
   5217         *content_size_ideal = window->ContentSizeIdeal;
   5218         return;
   5219     }
   5220 
   5221     content_size_current->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
   5222     content_size_current->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
   5223     content_size_ideal->x = (window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : IM_FLOOR(ImMax(window->DC.CursorMaxPos.x, window->DC.IdealMaxPos.x) - window->DC.CursorStartPos.x);
   5224     content_size_ideal->y = (window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : IM_FLOOR(ImMax(window->DC.CursorMaxPos.y, window->DC.IdealMaxPos.y) - window->DC.CursorStartPos.y);
   5225 }
   5226 
   5227 static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)
   5228 {
   5229     ImGuiContext& g = *GImGui;
   5230     ImGuiStyle& style = g.Style;
   5231     const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
   5232     ImVec2 size_pad = window->WindowPadding * 2.0f;
   5233     ImVec2 size_desired = size_contents + size_pad + ImVec2(0.0f, decoration_up_height);
   5234     if (window->Flags & ImGuiWindowFlags_Tooltip)
   5235     {
   5236         // Tooltip always resize
   5237         return size_desired;
   5238     }
   5239     else
   5240     {
   5241         // Maximum window size is determined by the viewport size or monitor size
   5242         const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
   5243         const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
   5244         ImVec2 size_min = style.WindowMinSize;
   5245         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)
   5246             size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
   5247 
   5248         // FIXME-VIEWPORT-WORKAREA: May want to use GetWorkSize() instead of Size depending on the type of windows?
   5249         ImVec2 avail_size = ImGui::GetMainViewport()->Size;
   5250         ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, avail_size - style.DisplaySafeAreaPadding * 2.0f));
   5251 
   5252         // When the window cannot fit all contents (either because of constraints, either because screen is too small),
   5253         // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
   5254         ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
   5255         bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - 0.0f                 < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
   5256         bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_up_height < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
   5257         if (will_have_scrollbar_x)
   5258             size_auto_fit.y += style.ScrollbarSize;
   5259         if (will_have_scrollbar_y)
   5260             size_auto_fit.x += style.ScrollbarSize;
   5261         return size_auto_fit;
   5262     }
   5263 }
   5264 
   5265 ImVec2 ImGui::CalcWindowNextAutoFitSize(ImGuiWindow* window)
   5266 {
   5267     ImVec2 size_contents_current;
   5268     ImVec2 size_contents_ideal;
   5269     CalcWindowContentSizes(window, &size_contents_current, &size_contents_ideal);
   5270     ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents_ideal);
   5271     ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);
   5272     return size_final;
   5273 }
   5274 
   5275 static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
   5276 {
   5277     if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
   5278         return ImGuiCol_PopupBg;
   5279     if (flags & ImGuiWindowFlags_ChildWindow)
   5280         return ImGuiCol_ChildBg;
   5281     return ImGuiCol_WindowBg;
   5282 }
   5283 
   5284 static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
   5285 {
   5286     ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm);                // Expected window upper-left
   5287     ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
   5288     ImVec2 size_expected = pos_max - pos_min;
   5289     ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);
   5290     *out_pos = pos_min;
   5291     if (corner_norm.x == 0.0f)
   5292         out_pos->x -= (size_constrained.x - size_expected.x);
   5293     if (corner_norm.y == 0.0f)
   5294         out_pos->y -= (size_constrained.y - size_expected.y);
   5295     *out_size = size_constrained;
   5296 }
   5297 
   5298 // Data for resizing from corner
   5299 struct ImGuiResizeGripDef
   5300 {
   5301     ImVec2  CornerPosN;
   5302     ImVec2  InnerDir;
   5303     int     AngleMin12, AngleMax12;
   5304 };
   5305 static const ImGuiResizeGripDef resize_grip_def[4] =
   5306 {
   5307     { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 },  // Lower-right
   5308     { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 },  // Lower-left
   5309     { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 },  // Upper-left (Unused)
   5310     { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }  // Upper-right (Unused)
   5311 };
   5312 
   5313 // Data for resizing from borders
   5314 struct ImGuiResizeBorderDef
   5315 {
   5316     ImVec2 InnerDir;
   5317     ImVec2 SegmentN1, SegmentN2;
   5318     float  OuterAngle;
   5319 };
   5320 static const ImGuiResizeBorderDef resize_border_def[4] =
   5321 {
   5322     { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f }, // Left
   5323     { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right
   5324     { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Up
   5325     { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }  // Down
   5326 };
   5327 
   5328 static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
   5329 {
   5330     ImRect rect = window->Rect();
   5331     if (thickness == 0.0f)
   5332         rect.Max -= ImVec2(1, 1);
   5333     if (border_n == ImGuiDir_Left)  { return ImRect(rect.Min.x - thickness,    rect.Min.y + perp_padding, rect.Min.x + thickness,    rect.Max.y - perp_padding); }
   5334     if (border_n == ImGuiDir_Right) { return ImRect(rect.Max.x - thickness,    rect.Min.y + perp_padding, rect.Max.x + thickness,    rect.Max.y - perp_padding); }
   5335     if (border_n == ImGuiDir_Up)    { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness,    rect.Max.x - perp_padding, rect.Min.y + thickness);    }
   5336     if (border_n == ImGuiDir_Down)  { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness,    rect.Max.x - perp_padding, rect.Max.y + thickness);    }
   5337     IM_ASSERT(0);
   5338     return ImRect();
   5339 }
   5340 
   5341 // 0..3: corners (Lower-right, Lower-left, Unused, Unused)
   5342 ImGuiID ImGui::GetWindowResizeCornerID(ImGuiWindow* window, int n)
   5343 {
   5344     IM_ASSERT(n >= 0 && n < 4);
   5345     ImGuiID id = window->ID;
   5346     id = ImHashStr("#RESIZE", 0, id);
   5347     id = ImHashData(&n, sizeof(int), id);
   5348     return id;
   5349 }
   5350 
   5351 // Borders (Left, Right, Up, Down)
   5352 ImGuiID ImGui::GetWindowResizeBorderID(ImGuiWindow* window, ImGuiDir dir)
   5353 {
   5354     IM_ASSERT(dir >= 0 && dir < 4);
   5355     int n = (int)dir + 4;
   5356     ImGuiID id = window->ID;
   5357     id = ImHashStr("#RESIZE", 0, id);
   5358     id = ImHashData(&n, sizeof(int), id);
   5359     return id;
   5360 }
   5361 
   5362 // Handle resize for: Resize Grips, Borders, Gamepad
   5363 // Return true when using auto-fit (double click on resize grip)
   5364 static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect)
   5365 {
   5366     ImGuiContext& g = *GImGui;
   5367     ImGuiWindowFlags flags = window->Flags;
   5368 
   5369     if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
   5370         return false;
   5371     if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
   5372         return false;
   5373 
   5374     bool ret_auto_fit = false;
   5375     const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
   5376     const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
   5377     const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);
   5378     const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_HOVER_PADDING : 0.0f;
   5379 
   5380     ImVec2 pos_target(FLT_MAX, FLT_MAX);
   5381     ImVec2 size_target(FLT_MAX, FLT_MAX);
   5382 
   5383     // Resize grips and borders are on layer 1
   5384     window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
   5385 
   5386     // Manual resize grips
   5387     PushID("#RESIZE");
   5388     for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
   5389     {
   5390         const ImGuiResizeGripDef& def = resize_grip_def[resize_grip_n];
   5391         const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, def.CornerPosN);
   5392 
   5393         // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
   5394         bool hovered, held;
   5395         ImRect resize_rect(corner - def.InnerDir * grip_hover_outer_size, corner + def.InnerDir * grip_hover_inner_size);
   5396         if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
   5397         if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
   5398         ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID()
   5399         ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
   5400         //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
   5401         if (hovered || held)
   5402             g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
   5403 
   5404         if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
   5405         {
   5406             // Manual auto-fit when double-clicking
   5407             size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
   5408             ret_auto_fit = true;
   5409             ClearActiveID();
   5410         }
   5411         else if (held)
   5412         {
   5413             // Resize from any of the four corners
   5414             // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
   5415             ImVec2 clamp_min = ImVec2(def.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, def.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
   5416             ImVec2 clamp_max = ImVec2(def.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, def.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
   5417             ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(def.InnerDir * grip_hover_outer_size, def.InnerDir * -grip_hover_inner_size, def.CornerPosN); // Corner of the window corresponding to our corner grip
   5418             corner_target = ImClamp(corner_target, clamp_min, clamp_max);
   5419             CalcResizePosSizeFromAnyCorner(window, corner_target, def.CornerPosN, &pos_target, &size_target);
   5420         }
   5421 
   5422         // Only lower-left grip is visible before hovering/activating
   5423         if (resize_grip_n == 0 || held || hovered)
   5424             resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
   5425     }
   5426     for (int border_n = 0; border_n < resize_border_count; border_n++)
   5427     {
   5428         const ImGuiResizeBorderDef& def = resize_border_def[border_n];
   5429         const ImGuiAxis axis = (border_n == ImGuiDir_Left || border_n == ImGuiDir_Right) ? ImGuiAxis_X : ImGuiAxis_Y;
   5430 
   5431         bool hovered, held;
   5432         ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING);
   5433         ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()
   5434         ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren);
   5435         //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
   5436         if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
   5437         {
   5438             g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
   5439             if (held)
   5440                 *border_held = border_n;
   5441         }
   5442         if (held)
   5443         {
   5444             ImVec2 clamp_min(border_n == ImGuiDir_Right ? visibility_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down ? visibility_rect.Min.y : -FLT_MAX);
   5445             ImVec2 clamp_max(border_n == ImGuiDir_Left  ? visibility_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up   ? visibility_rect.Max.y : +FLT_MAX);
   5446             ImVec2 border_target = window->Pos;
   5447             border_target[axis] = g.IO.MousePos[axis] - g.ActiveIdClickOffset[axis] + WINDOWS_HOVER_PADDING;
   5448             border_target = ImClamp(border_target, clamp_min, clamp_max);
   5449             CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target);
   5450         }
   5451     }
   5452     PopID();
   5453 
   5454     // Restore nav layer
   5455     window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
   5456 
   5457     // Navigation resize (keyboard/gamepad)
   5458     if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window)
   5459     {
   5460         ImVec2 nav_resize_delta;
   5461         if (g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift)
   5462             nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
   5463         if (g.NavInputSource == ImGuiInputSource_Gamepad)
   5464             nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down);
   5465         if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
   5466         {
   5467             const float NAV_RESIZE_SPEED = 600.0f;
   5468             nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
   5469             nav_resize_delta = ImMax(nav_resize_delta, visibility_rect.Min - window->Pos - window->Size);
   5470             g.NavWindowingToggleLayer = false;
   5471             g.NavDisableMouseHover = true;
   5472             resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
   5473             // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
   5474             size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
   5475         }
   5476     }
   5477 
   5478     // Apply back modified position/size to window
   5479     if (size_target.x != FLT_MAX)
   5480     {
   5481         window->SizeFull = size_target;
   5482         MarkIniSettingsDirty(window);
   5483     }
   5484     if (pos_target.x != FLT_MAX)
   5485     {
   5486         window->Pos = ImFloor(pos_target);
   5487         MarkIniSettingsDirty(window);
   5488     }
   5489 
   5490     window->Size = window->SizeFull;
   5491     return ret_auto_fit;
   5492 }
   5493 
   5494 static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& visibility_rect)
   5495 {
   5496     ImGuiContext& g = *GImGui;
   5497     ImVec2 size_for_clamping = window->Size;
   5498     if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
   5499         size_for_clamping.y = window->TitleBarHeight();
   5500     window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
   5501 }
   5502 
   5503 static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
   5504 {
   5505     ImGuiContext& g = *GImGui;
   5506     float rounding = window->WindowRounding;
   5507     float border_size = window->WindowBorderSize;
   5508     if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))
   5509         window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
   5510 
   5511     int border_held = window->ResizeBorderHeld;
   5512     if (border_held != -1)
   5513     {
   5514         const ImGuiResizeBorderDef& def = resize_border_def[border_held];
   5515         ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
   5516         window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
   5517         window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.SegmentN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
   5518         window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), 0, ImMax(2.0f, border_size)); // Thicker than usual
   5519     }
   5520     if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
   5521     {
   5522         float y = window->Pos.y + window->TitleBarHeight() - 1;
   5523         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);
   5524     }
   5525 }
   5526 
   5527 // Draw background and borders
   5528 // Draw and handle scrollbars
   5529 void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)
   5530 {
   5531     ImGuiContext& g = *GImGui;
   5532     ImGuiStyle& style = g.Style;
   5533     ImGuiWindowFlags flags = window->Flags;
   5534 
   5535     // Ensure that ScrollBar doesn't read last frame's SkipItems
   5536     IM_ASSERT(window->BeginCount == 0);
   5537     window->SkipItems = false;
   5538 
   5539     // Draw window + handle manual resize
   5540     // 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.
   5541     const float window_rounding = window->WindowRounding;
   5542     const float window_border_size = window->WindowBorderSize;
   5543     if (window->Collapsed)
   5544     {
   5545         // Title bar only
   5546         float backup_border_size = style.FrameBorderSize;
   5547         g.Style.FrameBorderSize = window->WindowBorderSize;
   5548         ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
   5549         RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
   5550         g.Style.FrameBorderSize = backup_border_size;
   5551     }
   5552     else
   5553     {
   5554         // Window background
   5555         if (!(flags & ImGuiWindowFlags_NoBackground))
   5556         {
   5557             ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
   5558             bool override_alpha = false;
   5559             float alpha = 1.0f;
   5560             if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
   5561             {
   5562                 alpha = g.NextWindowData.BgAlphaVal;
   5563                 override_alpha = true;
   5564             }
   5565             if (override_alpha)
   5566                 bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
   5567             window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);
   5568         }
   5569 
   5570         // Title bar
   5571         if (!(flags & ImGuiWindowFlags_NoTitleBar))
   5572         {
   5573             ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
   5574             window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawFlags_RoundCornersTop);
   5575         }
   5576 
   5577         // Menu bar
   5578         if (flags & ImGuiWindowFlags_MenuBar)
   5579         {
   5580             ImRect menu_bar_rect = window->MenuBarRect();
   5581             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.
   5582             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, ImDrawFlags_RoundCornersTop);
   5583             if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
   5584                 window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
   5585         }
   5586 
   5587         // Scrollbars
   5588         if (window->ScrollbarX)
   5589             Scrollbar(ImGuiAxis_X);
   5590         if (window->ScrollbarY)
   5591             Scrollbar(ImGuiAxis_Y);
   5592 
   5593         // Render resize grips (after their input handling so we don't have a frame of latency)
   5594         if (!(flags & ImGuiWindowFlags_NoResize))
   5595         {
   5596             for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
   5597             {
   5598                 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
   5599                 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
   5600                 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)));
   5601                 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)));
   5602                 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);
   5603                 window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
   5604             }
   5605         }
   5606 
   5607         // Borders
   5608         RenderWindowOuterBorders(window);
   5609     }
   5610 }
   5611 
   5612 // Render title text, collapse button, close button
   5613 void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
   5614 {
   5615     ImGuiContext& g = *GImGui;
   5616     ImGuiStyle& style = g.Style;
   5617     ImGuiWindowFlags flags = window->Flags;
   5618 
   5619     const bool has_close_button = (p_open != NULL);
   5620     const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
   5621 
   5622     // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
   5623     const ImGuiItemFlags item_flags_backup = g.CurrentItemFlags;
   5624     g.CurrentItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
   5625     window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
   5626 
   5627     // Layout buttons
   5628     // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
   5629     float pad_l = style.FramePadding.x;
   5630     float pad_r = style.FramePadding.x;
   5631     float button_sz = g.FontSize;
   5632     ImVec2 close_button_pos;
   5633     ImVec2 collapse_button_pos;
   5634     if (has_close_button)
   5635     {
   5636         pad_r += button_sz;
   5637         close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
   5638     }
   5639     if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
   5640     {
   5641         pad_r += button_sz;
   5642         collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
   5643     }
   5644     if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
   5645     {
   5646         collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
   5647         pad_l += button_sz;
   5648     }
   5649 
   5650     // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
   5651     if (has_collapse_button)
   5652         if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos))
   5653             window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
   5654 
   5655     // Close button
   5656     if (has_close_button)
   5657         if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
   5658             *p_open = false;
   5659 
   5660     window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
   5661     g.CurrentItemFlags = item_flags_backup;
   5662 
   5663     // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
   5664     // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
   5665     const char* UNSAVED_DOCUMENT_MARKER = "*";
   5666     const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
   5667     const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
   5668 
   5669     // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
   5670     // while uncentered title text will still reach edges correctly.
   5671     if (pad_l > style.FramePadding.x)
   5672         pad_l += g.Style.ItemInnerSpacing.x;
   5673     if (pad_r > style.FramePadding.x)
   5674         pad_r += g.Style.ItemInnerSpacing.x;
   5675     if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
   5676     {
   5677         float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
   5678         float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
   5679         pad_l = ImMax(pad_l, pad_extend * centerness);
   5680         pad_r = ImMax(pad_r, pad_extend * centerness);
   5681     }
   5682 
   5683     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);
   5684     ImRect clip_r(layout_r.Min.x, layout_r.Min.y, ImMin(layout_r.Max.x + g.Style.ItemInnerSpacing.x, title_bar_rect.Max.x), layout_r.Max.y);
   5685     //if (g.IO.KeyShift) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
   5686     //if (g.IO.KeyCtrl) window->DrawList->AddRect(clip_r.Min, clip_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
   5687     RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
   5688     if (flags & ImGuiWindowFlags_UnsavedDocument)
   5689     {
   5690         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);
   5691         ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f));
   5692         RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
   5693     }
   5694 }
   5695 
   5696 void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
   5697 {
   5698     window->ParentWindow = parent_window;
   5699     window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
   5700     if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
   5701         window->RootWindow = parent_window->RootWindow;
   5702     if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
   5703         window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
   5704     while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
   5705     {
   5706         IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
   5707         window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
   5708     }
   5709 }
   5710 
   5711 // Push a new Dear ImGui window to add widgets to.
   5712 // - 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.
   5713 // - Begin/End can be called multiple times during the frame with the same window name to append content.
   5714 // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
   5715 //   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.
   5716 // - 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.
   5717 // - 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.
   5718 bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
   5719 {
   5720     ImGuiContext& g = *GImGui;
   5721     const ImGuiStyle& style = g.Style;
   5722     IM_ASSERT(name != NULL && name[0] != '\0');     // Window name required
   5723     IM_ASSERT(g.WithinFrameScope);                  // Forgot to call ImGui::NewFrame()
   5724     IM_ASSERT(g.FrameCountEnded != g.FrameCount);   // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
   5725 
   5726     // Find or create
   5727     ImGuiWindow* window = FindWindowByName(name);
   5728     const bool window_just_created = (window == NULL);
   5729     if (window_just_created)
   5730         window = CreateNewWindow(name, flags);
   5731 
   5732     // Automatically disable manual moving/resizing when NoInputs is set
   5733     if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
   5734         flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
   5735 
   5736     if (flags & ImGuiWindowFlags_NavFlattened)
   5737         IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
   5738 
   5739     const int current_frame = g.FrameCount;
   5740     const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
   5741     window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);
   5742 
   5743     // Update the Appearing flag
   5744     bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1);   // Not using !WasActive because the implicit "Debug" window would always toggle off->on
   5745     if (flags & ImGuiWindowFlags_Popup)
   5746     {
   5747         ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
   5748         window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
   5749         window_just_activated_by_user |= (window != popup_ref.Window);
   5750     }
   5751     window->Appearing = window_just_activated_by_user;
   5752     if (window->Appearing)
   5753         SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
   5754 
   5755     // Update Flags, LastFrameActive, BeginOrderXXX fields
   5756     if (first_begin_of_the_frame)
   5757     {
   5758         window->Flags = (ImGuiWindowFlags)flags;
   5759         window->LastFrameActive = current_frame;
   5760         window->LastTimeActive = (float)g.Time;
   5761         window->BeginOrderWithinParent = 0;
   5762         window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
   5763     }
   5764     else
   5765     {
   5766         flags = window->Flags;
   5767     }
   5768 
   5769     // 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
   5770     ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
   5771     ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
   5772     IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
   5773 
   5774     // We allow window memory to be compacted so recreate the base stack when needed.
   5775     if (window->IDStack.Size == 0)
   5776         window->IDStack.push_back(window->ID);
   5777 
   5778     // Add to stack
   5779     // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
   5780     g.CurrentWindowStack.push_back(window);
   5781     g.CurrentWindow = window;
   5782     window->DC.StackSizesOnBegin.SetToCurrentState();
   5783     g.CurrentWindow = NULL;
   5784 
   5785     if (flags & ImGuiWindowFlags_Popup)
   5786     {
   5787         ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
   5788         popup_ref.Window = window;
   5789         g.BeginPopupStack.push_back(popup_ref);
   5790         window->PopupId = popup_ref.PopupId;
   5791     }
   5792 
   5793     // Update ->RootWindow and others pointers (before any possible call to FocusWindow)
   5794     if (first_begin_of_the_frame)
   5795         UpdateWindowParentAndRootLinks(window, flags, parent_window);
   5796 
   5797     // Process SetNextWindow***() calls
   5798     // (FIXME: Consider splitting the HasXXX flags into X/Y components
   5799     bool window_pos_set_by_api = false;
   5800     bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
   5801     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)
   5802     {
   5803         window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
   5804         if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
   5805         {
   5806             // May be processed on the next frame if this is our first frame and we are measuring size
   5807             // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
   5808             window->SetWindowPosVal = g.NextWindowData.PosVal;
   5809             window->SetWindowPosPivot = g.NextWindowData.PosPivotVal;
   5810             window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
   5811         }
   5812         else
   5813         {
   5814             SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
   5815         }
   5816     }
   5817     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)
   5818     {
   5819         window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
   5820         window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
   5821         SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
   5822     }
   5823     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll)
   5824     {
   5825         if (g.NextWindowData.ScrollVal.x >= 0.0f)
   5826         {
   5827             window->ScrollTarget.x = g.NextWindowData.ScrollVal.x;
   5828             window->ScrollTargetCenterRatio.x = 0.0f;
   5829         }
   5830         if (g.NextWindowData.ScrollVal.y >= 0.0f)
   5831         {
   5832             window->ScrollTarget.y = g.NextWindowData.ScrollVal.y;
   5833             window->ScrollTargetCenterRatio.y = 0.0f;
   5834         }
   5835     }
   5836     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)
   5837         window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal;
   5838     else if (first_begin_of_the_frame)
   5839         window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
   5840     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)
   5841         SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
   5842     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
   5843         FocusWindow(window);
   5844     if (window->Appearing)
   5845         SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
   5846 
   5847     // When reusing window again multiple times a frame, just append content (don't need to setup again)
   5848     if (first_begin_of_the_frame)
   5849     {
   5850         // Initialize
   5851         const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
   5852         window->Active = true;
   5853         window->HasCloseButton = (p_open != NULL);
   5854         window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
   5855         window->IDStack.resize(1);
   5856         window->DrawList->_ResetForNewFrame();
   5857         window->DC.CurrentTableIdx = -1;
   5858 
   5859         // Restore buffer capacity when woken from a compacted state, to avoid
   5860         if (window->MemoryCompacted)
   5861             GcAwakeTransientWindowBuffers(window);
   5862 
   5863         // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
   5864         // 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.
   5865         bool window_title_visible_elsewhere = false;
   5866         if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0)   // Window titles visible when using CTRL+TAB
   5867             window_title_visible_elsewhere = true;
   5868         if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
   5869         {
   5870             size_t buf_len = (size_t)window->NameBufLen;
   5871             window->Name = ImStrdupcpy(window->Name, &buf_len, name);
   5872             window->NameBufLen = (int)buf_len;
   5873         }
   5874 
   5875         // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
   5876 
   5877         // Update contents size from last frame for auto-fitting (or use explicit size)
   5878         const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
   5879         CalcWindowContentSizes(window, &window->ContentSize, &window->ContentSizeIdeal);
   5880         if (window->HiddenFramesCanSkipItems > 0)
   5881             window->HiddenFramesCanSkipItems--;
   5882         if (window->HiddenFramesCannotSkipItems > 0)
   5883             window->HiddenFramesCannotSkipItems--;
   5884         if (window->HiddenFramesForRenderOnly > 0)
   5885             window->HiddenFramesForRenderOnly--;
   5886 
   5887         // Hide new windows for one frame until they calculate their size
   5888         if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
   5889             window->HiddenFramesCannotSkipItems = 1;
   5890 
   5891         // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
   5892         // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
   5893         if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
   5894         {
   5895             window->HiddenFramesCannotSkipItems = 1;
   5896             if (flags & ImGuiWindowFlags_AlwaysAutoResize)
   5897             {
   5898                 if (!window_size_x_set_by_api)
   5899                     window->Size.x = window->SizeFull.x = 0.f;
   5900                 if (!window_size_y_set_by_api)
   5901                     window->Size.y = window->SizeFull.y = 0.f;
   5902                 window->ContentSize = window->ContentSizeIdeal = ImVec2(0.f, 0.f);
   5903             }
   5904         }
   5905 
   5906         // SELECT VIEWPORT
   5907         // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style)
   5908         SetCurrentWindow(window);
   5909 
   5910         // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)
   5911 
   5912         if (flags & ImGuiWindowFlags_ChildWindow)
   5913             window->WindowBorderSize = style.ChildBorderSize;
   5914         else
   5915             window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
   5916         window->WindowPadding = style.WindowPadding;
   5917         if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)
   5918             window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
   5919 
   5920         // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size.
   5921         window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
   5922         window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
   5923 
   5924         // Collapse window by double-clicking on title bar
   5925         // 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
   5926         if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
   5927         {
   5928             // 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.
   5929             ImRect title_bar_rect = window->TitleBarRect();
   5930             if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])
   5931                 window->WantCollapseToggle = true;
   5932             if (window->WantCollapseToggle)
   5933             {
   5934                 window->Collapsed = !window->Collapsed;
   5935                 MarkIniSettingsDirty(window);
   5936             }
   5937         }
   5938         else
   5939         {
   5940             window->Collapsed = false;
   5941         }
   5942         window->WantCollapseToggle = false;
   5943 
   5944         // SIZE
   5945 
   5946         // Calculate auto-fit size, handle automatic resize
   5947         const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSizeIdeal);
   5948         bool use_current_size_for_scrollbar_x = window_just_created;
   5949         bool use_current_size_for_scrollbar_y = window_just_created;
   5950         if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
   5951         {
   5952             // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
   5953             if (!window_size_x_set_by_api)
   5954             {
   5955                 window->SizeFull.x = size_auto_fit.x;
   5956                 use_current_size_for_scrollbar_x = true;
   5957             }
   5958             if (!window_size_y_set_by_api)
   5959             {
   5960                 window->SizeFull.y = size_auto_fit.y;
   5961                 use_current_size_for_scrollbar_y = true;
   5962             }
   5963         }
   5964         else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
   5965         {
   5966             // Auto-fit may only grow window during the first few frames
   5967             // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
   5968             if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
   5969             {
   5970                 window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
   5971                 use_current_size_for_scrollbar_x = true;
   5972             }
   5973             if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
   5974             {
   5975                 window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
   5976                 use_current_size_for_scrollbar_y = true;
   5977             }
   5978             if (!window->Collapsed)
   5979                 MarkIniSettingsDirty(window);
   5980         }
   5981 
   5982         // Apply minimum/maximum window size constraints and final size
   5983         window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);
   5984         window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
   5985 
   5986         // Decoration size
   5987         const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
   5988 
   5989         // POSITION
   5990 
   5991         // Popup latch its initial position, will position itself when it appears next frame
   5992         if (window_just_activated_by_user)
   5993         {
   5994             window->AutoPosLastDirection = ImGuiDir_None;
   5995             if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos()
   5996                 window->Pos = g.BeginPopupStack.back().OpenPopupPos;
   5997         }
   5998 
   5999         // Position child window
   6000         if (flags & ImGuiWindowFlags_ChildWindow)
   6001         {
   6002             IM_ASSERT(parent_window && parent_window->Active);
   6003             window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
   6004             parent_window->DC.ChildWindows.push_back(window);
   6005             if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
   6006                 window->Pos = parent_window->DC.CursorPos;
   6007         }
   6008 
   6009         const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);
   6010         if (window_pos_with_pivot)
   6011             SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering)
   6012         else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
   6013             window->Pos = FindBestWindowPosForPopup(window);
   6014         else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
   6015             window->Pos = FindBestWindowPosForPopup(window);
   6016         else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
   6017             window->Pos = FindBestWindowPosForPopup(window);
   6018 
   6019         // Calculate the range of allowed position for that window (to be movable and visible past safe area padding)
   6020         // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect.
   6021         ImGuiViewportP* viewport = (ImGuiViewportP*)(void*)GetMainViewport();
   6022         ImRect viewport_rect(viewport->GetMainRect());
   6023         ImRect viewport_work_rect(viewport->GetWorkRect());
   6024         ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
   6025         ImRect visibility_rect(viewport_work_rect.Min + visibility_padding, viewport_work_rect.Max - visibility_padding);
   6026 
   6027         // Clamp position/size so window stays visible within its viewport or monitor
   6028         // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
   6029         if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
   6030             if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f)
   6031                 ClampWindowRect(window, visibility_rect);
   6032         window->Pos = ImFloor(window->Pos);
   6033 
   6034         // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
   6035         // Large values tend to lead to variety of artifacts and are not recommended.
   6036         window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
   6037 
   6038         // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts.
   6039         //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar))
   6040         //    window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f);
   6041 
   6042         // Apply window focus (new and reactivated windows are moved to front)
   6043         bool want_focus = false;
   6044         if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
   6045         {
   6046             if (flags & ImGuiWindowFlags_Popup)
   6047                 want_focus = true;
   6048             else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
   6049                 want_focus = true;
   6050         }
   6051 
   6052         // Handle manual resize: Resize Grips, Borders, Gamepad
   6053         int border_held = -1;
   6054         ImU32 resize_grip_col[4] = {};
   6055         const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
   6056         const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
   6057         if (!window->Collapsed)
   6058             if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
   6059                 use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
   6060         window->ResizeBorderHeld = (signed char)border_held;
   6061 
   6062         // SCROLLBAR VISIBILITY
   6063 
   6064         // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).
   6065         if (!window->Collapsed)
   6066         {
   6067             // When reading the current size we need to read it after size constraints have been applied.
   6068             // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again.
   6069             ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height);
   6070             ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes;
   6071             ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
   6072             float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
   6073             float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
   6074             //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
   6075             window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
   6076             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));
   6077             if (window->ScrollbarX && !window->ScrollbarY)
   6078                 window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
   6079             window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
   6080         }
   6081 
   6082         // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)
   6083         // Update various regions. Variables they depends on should be set above in this function.
   6084         // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.
   6085 
   6086         // Outer rectangle
   6087         // Not affected by window border size. Used by:
   6088         // - FindHoveredWindow() (w/ extra padding when border resize is enabled)
   6089         // - Begin() initial clipping rect for drawing window background and borders.
   6090         // - Begin() clipping whole child
   6091         const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
   6092         const ImRect outer_rect = window->Rect();
   6093         const ImRect title_bar_rect = window->TitleBarRect();
   6094         window->OuterRectClipped = outer_rect;
   6095         window->OuterRectClipped.ClipWith(host_rect);
   6096 
   6097         // Inner rectangle
   6098         // Not affected by window border size. Used by:
   6099         // - InnerClipRect
   6100         // - ScrollToBringRectIntoView()
   6101         // - NavUpdatePageUpPageDown()
   6102         // - Scrollbar()
   6103         window->InnerRect.Min.x = window->Pos.x;
   6104         window->InnerRect.Min.y = window->Pos.y + decoration_up_height;
   6105         window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x;
   6106         window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y;
   6107 
   6108         // Inner clipping rectangle.
   6109         // Will extend a little bit outside the normal work region.
   6110         // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
   6111         // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
   6112         // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
   6113         // Affected by window/frame border size. Used by:
   6114         // - Begin() initial clip rect
   6115         float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
   6116         window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
   6117         window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
   6118         window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
   6119         window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
   6120         window->InnerClipRect.ClipWithFull(host_rect);
   6121 
   6122         // Default item width. Make it proportional to window size if window manually resizes
   6123         if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
   6124             window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f);
   6125         else
   6126             window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f);
   6127 
   6128         // SCROLLING
   6129 
   6130         // Lock down maximum scrolling
   6131         // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate
   6132         // for right/bottom aligned items without creating a scrollbar.
   6133         window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
   6134         window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
   6135 
   6136         // Apply scrolling
   6137         window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);
   6138         window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
   6139 
   6140         // DRAWING
   6141 
   6142         // Setup draw list and outer clipping rectangle
   6143         IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0);
   6144         window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
   6145         PushClipRect(host_rect.Min, host_rect.Max, false);
   6146 
   6147         // Draw modal window background (darkens what is behind them, all viewports)
   6148         const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
   6149         const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow);
   6150         if (dim_bg_for_modal || dim_bg_for_window_list)
   6151         {
   6152             const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
   6153             window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col);
   6154         }
   6155 
   6156         // Draw navigation selection/windowing rectangle background
   6157         if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim)
   6158         {
   6159             ImRect bb = window->Rect();
   6160             bb.Expand(g.FontSize);
   6161             if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
   6162                 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
   6163         }
   6164 
   6165         // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call.
   6166         // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
   6167         // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child.
   6168         // We also disabled this when we have dimming overlay behind this specific one child.
   6169         // 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.
   6170         {
   6171             bool render_decorations_in_parent = false;
   6172             if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
   6173                 if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0)
   6174                     render_decorations_in_parent = true;
   6175             if (render_decorations_in_parent)
   6176                 window->DrawList = parent_window->DrawList;
   6177 
   6178             // Handle title bar, scrollbar, resize grips and resize borders
   6179             const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
   6180             const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
   6181             RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size);
   6182 
   6183             if (render_decorations_in_parent)
   6184                 window->DrawList = &window->DrawListInst;
   6185         }
   6186 
   6187         // Draw navigation selection/windowing rectangle border
   6188         if (g.NavWindowingTargetAnim == window)
   6189         {
   6190             float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
   6191             ImRect bb = window->Rect();
   6192             bb.Expand(g.FontSize);
   6193             if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
   6194             {
   6195                 bb.Expand(-g.FontSize - 1.0f);
   6196                 rounding = window->WindowRounding;
   6197             }
   6198             window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, 0, 3.0f);
   6199         }
   6200 
   6201         // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
   6202 
   6203         // Work rectangle.
   6204         // Affected by window padding and border size. Used by:
   6205         // - Columns() for right-most edge
   6206         // - TreeNode(), CollapsingHeader() for right-most edge
   6207         // - BeginTabBar() for right-most edge
   6208         const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
   6209         const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
   6210         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));
   6211         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));
   6212         window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
   6213         window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
   6214         window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
   6215         window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
   6216         window->ParentWorkRect = window->WorkRect;
   6217 
   6218         // [LEGACY] Content Region
   6219         // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
   6220         // Used by:
   6221         // - Mouse wheel scrolling + many other things
   6222         window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
   6223         window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
   6224         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));
   6225         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));
   6226 
   6227         // Setup drawing context
   6228         // (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.)
   6229         window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
   6230         window->DC.GroupOffset.x = 0.0f;
   6231         window->DC.ColumnsOffset.x = 0.0f;
   6232         window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y);
   6233         window->DC.CursorPos = window->DC.CursorStartPos;
   6234         window->DC.CursorPosPrevLine = window->DC.CursorPos;
   6235         window->DC.CursorMaxPos = window->DC.CursorStartPos;
   6236         window->DC.IdealMaxPos = window->DC.CursorStartPos;
   6237         window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
   6238         window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
   6239 
   6240         window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
   6241         window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext;
   6242         window->DC.NavLayersActiveMaskNext = 0x00;
   6243         window->DC.NavHideHighlightOneFrame = false;
   6244         window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
   6245 
   6246         window->DC.MenuBarAppending = false;
   6247         window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
   6248         window->DC.TreeDepth = 0;
   6249         window->DC.TreeJumpToParentOnPopMask = 0x00;
   6250         window->DC.ChildWindows.resize(0);
   6251         window->DC.StateStorage = &window->StateStorage;
   6252         window->DC.CurrentColumns = NULL;
   6253         window->DC.LayoutType = ImGuiLayoutType_Vertical;
   6254         window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
   6255         window->DC.FocusCounterRegular = window->DC.FocusCounterTabStop = -1;
   6256 
   6257         window->DC.ItemWidth = window->ItemWidthDefault;
   6258         window->DC.TextWrapPos = -1.0f; // disabled
   6259         window->DC.ItemWidthStack.resize(0);
   6260         window->DC.TextWrapPosStack.resize(0);
   6261 
   6262         if (window->AutoFitFramesX > 0)
   6263             window->AutoFitFramesX--;
   6264         if (window->AutoFitFramesY > 0)
   6265             window->AutoFitFramesY--;
   6266 
   6267         // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
   6268         if (want_focus)
   6269         {
   6270             FocusWindow(window);
   6271             NavInitWindow(window, false); // <-- this is in the way for us to be able to defer and sort reappearing FocusWindow() calls
   6272         }
   6273 
   6274         // Title bar
   6275         if (!(flags & ImGuiWindowFlags_NoTitleBar))
   6276             RenderWindowTitleBarContents(window, ImRect(title_bar_rect.Min.x + window->WindowBorderSize, title_bar_rect.Min.y, title_bar_rect.Max.x - window->WindowBorderSize, title_bar_rect.Max.y), name, p_open);
   6277 
   6278         // Clear hit test shape every frame
   6279         window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;
   6280 
   6281         // Pressing CTRL+C while holding on a window copy its content to the clipboard
   6282         // 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.
   6283         // Maybe we can support CTRL+C on every element?
   6284         /*
   6285         //if (g.NavWindow == window && g.ActiveId == 0)
   6286         if (g.ActiveId == window->MoveId)
   6287             if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
   6288                 LogToClipboard();
   6289         */
   6290 
   6291         // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
   6292         // This is useful to allow creating context menus on title bar only, etc.
   6293         SetLastItemData(window, window->MoveId, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
   6294 
   6295 #ifdef IMGUI_ENABLE_TEST_ENGINE
   6296         if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
   6297             IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId);
   6298 #endif
   6299     }
   6300     else
   6301     {
   6302         // Append
   6303         SetCurrentWindow(window);
   6304     }
   6305 
   6306     // Pull/inherit current state
   6307     g.CurrentItemFlags = g.ItemFlagsStack.back(); // Inherit from shared stack
   6308     window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // Inherit from parent only // -V595
   6309 
   6310     PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
   6311 
   6312     // 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)
   6313     window->WriteAccessed = false;
   6314     window->BeginCount++;
   6315     g.NextWindowData.ClearFlags();
   6316 
   6317     // Update visibility
   6318     if (first_begin_of_the_frame)
   6319     {
   6320         if (flags & ImGuiWindowFlags_ChildWindow)
   6321         {
   6322             // Child window can be out of sight and have "negative" clip windows.
   6323             // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
   6324             IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
   6325             if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0) // FIXME: Doesn't make sense for ChildWindow??
   6326                 if (!g.LogEnabled)
   6327                     if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
   6328                         window->HiddenFramesCanSkipItems = 1;
   6329 
   6330             // Hide along with parent or if parent is collapsed
   6331             if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
   6332                 window->HiddenFramesCanSkipItems = 1;
   6333             if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
   6334                 window->HiddenFramesCannotSkipItems = 1;
   6335         }
   6336 
   6337         // 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)
   6338         if (style.Alpha <= 0.0f)
   6339             window->HiddenFramesCanSkipItems = 1;
   6340 
   6341         // Update the Hidden flag
   6342         window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0) || (window->HiddenFramesForRenderOnly > 0);
   6343 
   6344         // Disable inputs for requested number of frames
   6345         if (window->DisableInputsFrames > 0)
   6346         {
   6347             window->DisableInputsFrames--;
   6348             window->Flags |= ImGuiWindowFlags_NoInputs;
   6349         }
   6350 
   6351         // Update the SkipItems flag, used to early out of all items functions (no layout required)
   6352         bool skip_items = false;
   6353         if (window->Collapsed || !window->Active || window->Hidden)
   6354             if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
   6355                 skip_items = true;
   6356         window->SkipItems = skip_items;
   6357     }
   6358 
   6359     return !window->SkipItems;
   6360 }
   6361 
   6362 void ImGui::End()
   6363 {
   6364     ImGuiContext& g = *GImGui;
   6365     ImGuiWindow* window = g.CurrentWindow;
   6366 
   6367     // Error checking: verify that user hasn't called End() too many times!
   6368     if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow)
   6369     {
   6370         IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
   6371         return;
   6372     }
   6373     IM_ASSERT(g.CurrentWindowStack.Size > 0);
   6374 
   6375     // Error checking: verify that user doesn't directly call End() on a child window.
   6376     if (window->Flags & ImGuiWindowFlags_ChildWindow)
   6377         IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!");
   6378 
   6379     // Close anything that is open
   6380     if (window->DC.CurrentColumns)
   6381         EndColumns();
   6382     PopClipRect();   // Inner window clip rectangle
   6383 
   6384     // Stop logging
   6385     if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging
   6386         LogFinish();
   6387 
   6388     // Pop from window stack
   6389     g.CurrentWindowStack.pop_back();
   6390     if (window->Flags & ImGuiWindowFlags_Popup)
   6391         g.BeginPopupStack.pop_back();
   6392     window->DC.StackSizesOnBegin.CompareWithCurrentState();
   6393     SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
   6394 }
   6395 
   6396 void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
   6397 {
   6398     ImGuiContext& g = *GImGui;
   6399     IM_ASSERT(window == window->RootWindow);
   6400 
   6401     const int cur_order = window->FocusOrder;
   6402     IM_ASSERT(g.WindowsFocusOrder[cur_order] == window);
   6403     if (g.WindowsFocusOrder.back() == window)
   6404         return;
   6405 
   6406     const int new_order = g.WindowsFocusOrder.Size - 1;
   6407     for (int n = cur_order; n < new_order; n++)
   6408     {
   6409         g.WindowsFocusOrder[n] = g.WindowsFocusOrder[n + 1];
   6410         g.WindowsFocusOrder[n]->FocusOrder--;
   6411         IM_ASSERT(g.WindowsFocusOrder[n]->FocusOrder == n);
   6412     }
   6413     g.WindowsFocusOrder[new_order] = window;
   6414     window->FocusOrder = (short)new_order;
   6415 }
   6416 
   6417 void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
   6418 {
   6419     ImGuiContext& g = *GImGui;
   6420     ImGuiWindow* current_front_window = g.Windows.back();
   6421     if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better)
   6422         return;
   6423     for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
   6424         if (g.Windows[i] == window)
   6425         {
   6426             memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
   6427             g.Windows[g.Windows.Size - 1] = window;
   6428             break;
   6429         }
   6430 }
   6431 
   6432 void ImGui::BringWindowToDisplayBack(ImGuiWindow* window)
   6433 {
   6434     ImGuiContext& g = *GImGui;
   6435     if (g.Windows[0] == window)
   6436         return;
   6437     for (int i = 0; i < g.Windows.Size; i++)
   6438         if (g.Windows[i] == window)
   6439         {
   6440             memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
   6441             g.Windows[0] = window;
   6442             break;
   6443         }
   6444 }
   6445 
   6446 // Moving window to front of display and set focus (which happens to be back of our sorted list)
   6447 void ImGui::FocusWindow(ImGuiWindow* window)
   6448 {
   6449     ImGuiContext& g = *GImGui;
   6450 
   6451     if (g.NavWindow != window)
   6452     {
   6453         g.NavWindow = window;
   6454         if (window && g.NavDisableMouseHover)
   6455             g.NavMousePosDirty = true;
   6456         g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
   6457         g.NavFocusScopeId = 0;
   6458         g.NavIdIsAlive = false;
   6459         g.NavLayer = ImGuiNavLayer_Main;
   6460         g.NavInitRequest = g.NavMoveRequest = false;
   6461         NavUpdateAnyRequestFlag();
   6462         //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
   6463     }
   6464 
   6465     // Close popups if any
   6466     ClosePopupsOverWindow(window, false);
   6467 
   6468     // Move the root window to the top of the pile
   6469     IM_ASSERT(window == NULL || window->RootWindow != NULL);
   6470     ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop
   6471     ImGuiWindow* display_front_window = window ? window->RootWindow : NULL;
   6472 
   6473     // Steal active widgets. Some of the cases it triggers includes:
   6474     // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run.
   6475     // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId)
   6476     if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)
   6477         if (!g.ActiveIdNoClearOnFocusLoss)
   6478             ClearActiveID();
   6479 
   6480     // Passing NULL allow to disable keyboard focus
   6481     if (!window)
   6482         return;
   6483 
   6484     // Bring to front
   6485     BringWindowToFocusFront(focus_front_window);
   6486     if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
   6487         BringWindowToDisplayFront(display_front_window);
   6488 }
   6489 
   6490 void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window)
   6491 {
   6492     ImGuiContext& g = *GImGui;
   6493 
   6494     const int start_idx = ((under_this_window != NULL) ? FindWindowFocusIndex(under_this_window) : g.WindowsFocusOrder.Size) - 1;
   6495     for (int i = start_idx; i >= 0; i--)
   6496     {
   6497         // 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.
   6498         ImGuiWindow* window = g.WindowsFocusOrder[i];
   6499         IM_ASSERT(window == window->RootWindow);
   6500         if (window != ignore_window && window->WasActive)
   6501             if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
   6502             {
   6503                 ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
   6504                 FocusWindow(focus_window);
   6505                 return;
   6506             }
   6507     }
   6508     FocusWindow(NULL);
   6509 }
   6510 
   6511 // Important: this alone doesn't alter current ImDrawList state. This is called by PushFont/PopFont only.
   6512 void ImGui::SetCurrentFont(ImFont* font)
   6513 {
   6514     ImGuiContext& g = *GImGui;
   6515     IM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
   6516     IM_ASSERT(font->Scale > 0.0f);
   6517     g.Font = font;
   6518     g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
   6519     g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
   6520 
   6521     ImFontAtlas* atlas = g.Font->ContainerAtlas;
   6522     g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
   6523     g.DrawListSharedData.TexUvLines = atlas->TexUvLines;
   6524     g.DrawListSharedData.Font = g.Font;
   6525     g.DrawListSharedData.FontSize = g.FontSize;
   6526 }
   6527 
   6528 void ImGui::PushFont(ImFont* font)
   6529 {
   6530     ImGuiContext& g = *GImGui;
   6531     if (!font)
   6532         font = GetDefaultFont();
   6533     SetCurrentFont(font);
   6534     g.FontStack.push_back(font);
   6535     g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
   6536 }
   6537 
   6538 void  ImGui::PopFont()
   6539 {
   6540     ImGuiContext& g = *GImGui;
   6541     g.CurrentWindow->DrawList->PopTextureID();
   6542     g.FontStack.pop_back();
   6543     SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
   6544 }
   6545 
   6546 void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
   6547 {
   6548     ImGuiContext& g = *GImGui;
   6549     ImGuiItemFlags item_flags = g.CurrentItemFlags;
   6550     IM_ASSERT(item_flags == g.ItemFlagsStack.back());
   6551     if (enabled)
   6552         item_flags |= option;
   6553     else
   6554         item_flags &= ~option;
   6555     g.CurrentItemFlags = item_flags;
   6556     g.ItemFlagsStack.push_back(item_flags);
   6557 }
   6558 
   6559 void ImGui::PopItemFlag()
   6560 {
   6561     ImGuiContext& g = *GImGui;
   6562     IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack.
   6563     g.ItemFlagsStack.pop_back();
   6564     g.CurrentItemFlags = g.ItemFlagsStack.back();
   6565 }
   6566 
   6567 // FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system.
   6568 void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
   6569 {
   6570     PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus);
   6571 }
   6572 
   6573 void ImGui::PopAllowKeyboardFocus()
   6574 {
   6575     PopItemFlag();
   6576 }
   6577 
   6578 void ImGui::PushButtonRepeat(bool repeat)
   6579 {
   6580     PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);
   6581 }
   6582 
   6583 void ImGui::PopButtonRepeat()
   6584 {
   6585     PopItemFlag();
   6586 }
   6587 
   6588 void ImGui::PushTextWrapPos(float wrap_pos_x)
   6589 {
   6590     ImGuiWindow* window = GetCurrentWindow();
   6591     window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos);
   6592     window->DC.TextWrapPos = wrap_pos_x;
   6593 }
   6594 
   6595 void ImGui::PopTextWrapPos()
   6596 {
   6597     ImGuiWindow* window = GetCurrentWindow();
   6598     window->DC.TextWrapPos = window->DC.TextWrapPosStack.back();
   6599     window->DC.TextWrapPosStack.pop_back();
   6600 }
   6601 
   6602 bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
   6603 {
   6604     if (window->RootWindow == potential_parent)
   6605         return true;
   6606     while (window != NULL)
   6607     {
   6608         if (window == potential_parent)
   6609             return true;
   6610         window = window->ParentWindow;
   6611     }
   6612     return false;
   6613 }
   6614 
   6615 bool ImGui::IsWindowAbove(ImGuiWindow* potential_above, ImGuiWindow* potential_below)
   6616 {
   6617     ImGuiContext& g = *GImGui;
   6618     for (int i = g.Windows.Size - 1; i >= 0; i--)
   6619     {
   6620         ImGuiWindow* candidate_window = g.Windows[i];
   6621         if (candidate_window == potential_above)
   6622             return true;
   6623         if (candidate_window == potential_below)
   6624             return false;
   6625     }
   6626     return false;
   6627 }
   6628 
   6629 bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)
   6630 {
   6631     IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0);   // Flags not supported by this function
   6632     ImGuiContext& g = *GImGui;
   6633     if (g.HoveredWindow == NULL)
   6634         return false;
   6635 
   6636     if ((flags & ImGuiHoveredFlags_AnyWindow) == 0)
   6637     {
   6638         ImGuiWindow* window = g.CurrentWindow;
   6639         switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows))
   6640         {
   6641         case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows:
   6642             if (g.HoveredWindow->RootWindow != window->RootWindow)
   6643                 return false;
   6644             break;
   6645         case ImGuiHoveredFlags_RootWindow:
   6646             if (g.HoveredWindow != window->RootWindow)
   6647                 return false;
   6648             break;
   6649         case ImGuiHoveredFlags_ChildWindows:
   6650             if (!IsWindowChildOf(g.HoveredWindow, window))
   6651                 return false;
   6652             break;
   6653         default:
   6654             if (g.HoveredWindow != window)
   6655                 return false;
   6656             break;
   6657         }
   6658     }
   6659 
   6660     if (!IsWindowContentHoverable(g.HoveredWindow, flags))
   6661         return false;
   6662     if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
   6663         if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
   6664             return false;
   6665     return true;
   6666 }
   6667 
   6668 bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
   6669 {
   6670     ImGuiContext& g = *GImGui;
   6671 
   6672     if (flags & ImGuiFocusedFlags_AnyWindow)
   6673         return g.NavWindow != NULL;
   6674 
   6675     IM_ASSERT(g.CurrentWindow);     // Not inside a Begin()/End()
   6676     switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))
   6677     {
   6678     case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:
   6679         return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
   6680     case ImGuiFocusedFlags_RootWindow:
   6681         return g.NavWindow == g.CurrentWindow->RootWindow;
   6682     case ImGuiFocusedFlags_ChildWindows:
   6683         return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
   6684     default:
   6685         return g.NavWindow == g.CurrentWindow;
   6686     }
   6687 }
   6688 
   6689 // Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
   6690 // Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically.
   6691 // If you want a window to never be focused, you may use the e.g. NoInputs flag.
   6692 bool ImGui::IsWindowNavFocusable(ImGuiWindow* window)
   6693 {
   6694     return window->WasActive && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);
   6695 }
   6696 
   6697 float ImGui::GetWindowWidth()
   6698 {
   6699     ImGuiWindow* window = GImGui->CurrentWindow;
   6700     return window->Size.x;
   6701 }
   6702 
   6703 float ImGui::GetWindowHeight()
   6704 {
   6705     ImGuiWindow* window = GImGui->CurrentWindow;
   6706     return window->Size.y;
   6707 }
   6708 
   6709 ImVec2 ImGui::GetWindowPos()
   6710 {
   6711     ImGuiContext& g = *GImGui;
   6712     ImGuiWindow* window = g.CurrentWindow;
   6713     return window->Pos;
   6714 }
   6715 
   6716 void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
   6717 {
   6718     // Test condition (NB: bit 0 is always true) and clear flags for next time
   6719     if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
   6720         return;
   6721 
   6722     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6723     window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
   6724     window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
   6725 
   6726     // Set
   6727     const ImVec2 old_pos = window->Pos;
   6728     window->Pos = ImFloor(pos);
   6729     ImVec2 offset = window->Pos - old_pos;
   6730     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
   6731     window->DC.CursorMaxPos += offset;      // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
   6732     window->DC.IdealMaxPos += offset;
   6733     window->DC.CursorStartPos += offset;
   6734 }
   6735 
   6736 void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
   6737 {
   6738     ImGuiWindow* window = GetCurrentWindowRead();
   6739     SetWindowPos(window, pos, cond);
   6740 }
   6741 
   6742 void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
   6743 {
   6744     if (ImGuiWindow* window = FindWindowByName(name))
   6745         SetWindowPos(window, pos, cond);
   6746 }
   6747 
   6748 ImVec2 ImGui::GetWindowSize()
   6749 {
   6750     ImGuiWindow* window = GetCurrentWindowRead();
   6751     return window->Size;
   6752 }
   6753 
   6754 void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
   6755 {
   6756     // Test condition (NB: bit 0 is always true) and clear flags for next time
   6757     if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
   6758         return;
   6759 
   6760     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6761     window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
   6762 
   6763     // Set
   6764     if (size.x > 0.0f)
   6765     {
   6766         window->AutoFitFramesX = 0;
   6767         window->SizeFull.x = IM_FLOOR(size.x);
   6768     }
   6769     else
   6770     {
   6771         window->AutoFitFramesX = 2;
   6772         window->AutoFitOnlyGrows = false;
   6773     }
   6774     if (size.y > 0.0f)
   6775     {
   6776         window->AutoFitFramesY = 0;
   6777         window->SizeFull.y = IM_FLOOR(size.y);
   6778     }
   6779     else
   6780     {
   6781         window->AutoFitFramesY = 2;
   6782         window->AutoFitOnlyGrows = false;
   6783     }
   6784 }
   6785 
   6786 void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
   6787 {
   6788     SetWindowSize(GImGui->CurrentWindow, size, cond);
   6789 }
   6790 
   6791 void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
   6792 {
   6793     if (ImGuiWindow* window = FindWindowByName(name))
   6794         SetWindowSize(window, size, cond);
   6795 }
   6796 
   6797 void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
   6798 {
   6799     // Test condition (NB: bit 0 is always true) and clear flags for next time
   6800     if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
   6801         return;
   6802     window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
   6803 
   6804     // Set
   6805     window->Collapsed = collapsed;
   6806 }
   6807 
   6808 void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size)
   6809 {
   6810     IM_ASSERT(window->HitTestHoleSize.x == 0);     // We don't support multiple holes/hit test filters
   6811     window->HitTestHoleSize = ImVec2ih(size);
   6812     window->HitTestHoleOffset = ImVec2ih(pos - window->Pos);
   6813 }
   6814 
   6815 void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
   6816 {
   6817     SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
   6818 }
   6819 
   6820 bool ImGui::IsWindowCollapsed()
   6821 {
   6822     ImGuiWindow* window = GetCurrentWindowRead();
   6823     return window->Collapsed;
   6824 }
   6825 
   6826 bool ImGui::IsWindowAppearing()
   6827 {
   6828     ImGuiWindow* window = GetCurrentWindowRead();
   6829     return window->Appearing;
   6830 }
   6831 
   6832 void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
   6833 {
   6834     if (ImGuiWindow* window = FindWindowByName(name))
   6835         SetWindowCollapsed(window, collapsed, cond);
   6836 }
   6837 
   6838 void ImGui::SetWindowFocus()
   6839 {
   6840     FocusWindow(GImGui->CurrentWindow);
   6841 }
   6842 
   6843 void ImGui::SetWindowFocus(const char* name)
   6844 {
   6845     if (name)
   6846     {
   6847         if (ImGuiWindow* window = FindWindowByName(name))
   6848             FocusWindow(window);
   6849     }
   6850     else
   6851     {
   6852         FocusWindow(NULL);
   6853     }
   6854 }
   6855 
   6856 void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
   6857 {
   6858     ImGuiContext& g = *GImGui;
   6859     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6860     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;
   6861     g.NextWindowData.PosVal = pos;
   6862     g.NextWindowData.PosPivotVal = pivot;
   6863     g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
   6864 }
   6865 
   6866 void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
   6867 {
   6868     ImGuiContext& g = *GImGui;
   6869     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6870     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;
   6871     g.NextWindowData.SizeVal = size;
   6872     g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
   6873 }
   6874 
   6875 void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
   6876 {
   6877     ImGuiContext& g = *GImGui;
   6878     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
   6879     g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
   6880     g.NextWindowData.SizeCallback = custom_callback;
   6881     g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
   6882 }
   6883 
   6884 // Content size = inner scrollable rectangle, padded with WindowPadding.
   6885 // SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
   6886 void ImGui::SetNextWindowContentSize(const ImVec2& size)
   6887 {
   6888     ImGuiContext& g = *GImGui;
   6889     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;
   6890     g.NextWindowData.ContentSizeVal = ImFloor(size);
   6891 }
   6892 
   6893 void ImGui::SetNextWindowScroll(const ImVec2& scroll)
   6894 {
   6895     ImGuiContext& g = *GImGui;
   6896     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll;
   6897     g.NextWindowData.ScrollVal = scroll;
   6898 }
   6899 
   6900 void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
   6901 {
   6902     ImGuiContext& g = *GImGui;
   6903     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
   6904     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;
   6905     g.NextWindowData.CollapsedVal = collapsed;
   6906     g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
   6907 }
   6908 
   6909 void ImGui::SetNextWindowFocus()
   6910 {
   6911     ImGuiContext& g = *GImGui;
   6912     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;
   6913 }
   6914 
   6915 void ImGui::SetNextWindowBgAlpha(float alpha)
   6916 {
   6917     ImGuiContext& g = *GImGui;
   6918     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;
   6919     g.NextWindowData.BgAlphaVal = alpha;
   6920 }
   6921 
   6922 ImDrawList* ImGui::GetWindowDrawList()
   6923 {
   6924     ImGuiWindow* window = GetCurrentWindow();
   6925     return window->DrawList;
   6926 }
   6927 
   6928 ImFont* ImGui::GetFont()
   6929 {
   6930     return GImGui->Font;
   6931 }
   6932 
   6933 float ImGui::GetFontSize()
   6934 {
   6935     return GImGui->FontSize;
   6936 }
   6937 
   6938 ImVec2 ImGui::GetFontTexUvWhitePixel()
   6939 {
   6940     return GImGui->DrawListSharedData.TexUvWhitePixel;
   6941 }
   6942 
   6943 void ImGui::SetWindowFontScale(float scale)
   6944 {
   6945     IM_ASSERT(scale > 0.0f);
   6946     ImGuiContext& g = *GImGui;
   6947     ImGuiWindow* window = GetCurrentWindow();
   6948     window->FontWindowScale = scale;
   6949     g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
   6950 }
   6951 
   6952 void ImGui::ActivateItem(ImGuiID id)
   6953 {
   6954     ImGuiContext& g = *GImGui;
   6955     g.NavNextActivateId = id;
   6956 }
   6957 
   6958 void ImGui::PushFocusScope(ImGuiID id)
   6959 {
   6960     ImGuiContext& g = *GImGui;
   6961     ImGuiWindow* window = g.CurrentWindow;
   6962     g.FocusScopeStack.push_back(window->DC.NavFocusScopeIdCurrent);
   6963     window->DC.NavFocusScopeIdCurrent = id;
   6964 }
   6965 
   6966 void ImGui::PopFocusScope()
   6967 {
   6968     ImGuiContext& g = *GImGui;
   6969     ImGuiWindow* window = g.CurrentWindow;
   6970     IM_ASSERT(g.FocusScopeStack.Size > 0); // Too many PopFocusScope() ?
   6971     window->DC.NavFocusScopeIdCurrent = g.FocusScopeStack.back();
   6972     g.FocusScopeStack.pop_back();
   6973 }
   6974 
   6975 void ImGui::SetKeyboardFocusHere(int offset)
   6976 {
   6977     IM_ASSERT(offset >= -1);    // -1 is allowed but not below
   6978     ImGuiContext& g = *GImGui;
   6979     ImGuiWindow* window = g.CurrentWindow;
   6980     g.TabFocusRequestNextWindow = window;
   6981     g.TabFocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset;
   6982     g.TabFocusRequestNextCounterTabStop = INT_MAX;
   6983 }
   6984 
   6985 void ImGui::SetItemDefaultFocus()
   6986 {
   6987     ImGuiContext& g = *GImGui;
   6988     ImGuiWindow* window = g.CurrentWindow;
   6989     if (!window->Appearing)
   6990         return;
   6991     if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == window->DC.NavLayerCurrent)
   6992     {
   6993         g.NavInitRequest = false;
   6994         g.NavInitResultId = window->DC.LastItemId;
   6995         g.NavInitResultRectRel = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
   6996         NavUpdateAnyRequestFlag();
   6997         if (!IsItemVisible())
   6998             SetScrollHereY();
   6999     }
   7000 }
   7001 
   7002 void ImGui::SetStateStorage(ImGuiStorage* tree)
   7003 {
   7004     ImGuiWindow* window = GImGui->CurrentWindow;
   7005     window->DC.StateStorage = tree ? tree : &window->StateStorage;
   7006 }
   7007 
   7008 ImGuiStorage* ImGui::GetStateStorage()
   7009 {
   7010     ImGuiWindow* window = GImGui->CurrentWindow;
   7011     return window->DC.StateStorage;
   7012 }
   7013 
   7014 void ImGui::PushID(const char* str_id)
   7015 {
   7016     ImGuiContext& g = *GImGui;
   7017     ImGuiWindow* window = g.CurrentWindow;
   7018     ImGuiID id = window->GetIDNoKeepAlive(str_id);
   7019     window->IDStack.push_back(id);
   7020 }
   7021 
   7022 void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
   7023 {
   7024     ImGuiContext& g = *GImGui;
   7025     ImGuiWindow* window = g.CurrentWindow;
   7026     ImGuiID id = window->GetIDNoKeepAlive(str_id_begin, str_id_end);
   7027     window->IDStack.push_back(id);
   7028 }
   7029 
   7030 void ImGui::PushID(const void* ptr_id)
   7031 {
   7032     ImGuiContext& g = *GImGui;
   7033     ImGuiWindow* window = g.CurrentWindow;
   7034     ImGuiID id = window->GetIDNoKeepAlive(ptr_id);
   7035     window->IDStack.push_back(id);
   7036 }
   7037 
   7038 void ImGui::PushID(int int_id)
   7039 {
   7040     ImGuiContext& g = *GImGui;
   7041     ImGuiWindow* window = g.CurrentWindow;
   7042     ImGuiID id = window->GetIDNoKeepAlive(int_id);
   7043     window->IDStack.push_back(id);
   7044 }
   7045 
   7046 // Push a given id value ignoring the ID stack as a seed.
   7047 void ImGui::PushOverrideID(ImGuiID id)
   7048 {
   7049     ImGuiContext& g = *GImGui;
   7050     ImGuiWindow* window = g.CurrentWindow;
   7051     window->IDStack.push_back(id);
   7052 }
   7053 
   7054 // Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call
   7055 // (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level.
   7056 //  for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more)
   7057 ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
   7058 {
   7059     ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
   7060     ImGui::KeepAliveID(id);
   7061 #ifdef IMGUI_ENABLE_TEST_ENGINE
   7062     ImGuiContext& g = *GImGui;
   7063     IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
   7064 #endif
   7065     return id;
   7066 }
   7067 
   7068 void ImGui::PopID()
   7069 {
   7070     ImGuiWindow* window = GImGui->CurrentWindow;
   7071     IM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window?
   7072     window->IDStack.pop_back();
   7073 }
   7074 
   7075 ImGuiID ImGui::GetID(const char* str_id)
   7076 {
   7077     ImGuiWindow* window = GImGui->CurrentWindow;
   7078     return window->GetID(str_id);
   7079 }
   7080 
   7081 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
   7082 {
   7083     ImGuiWindow* window = GImGui->CurrentWindow;
   7084     return window->GetID(str_id_begin, str_id_end);
   7085 }
   7086 
   7087 ImGuiID ImGui::GetID(const void* ptr_id)
   7088 {
   7089     ImGuiWindow* window = GImGui->CurrentWindow;
   7090     return window->GetID(ptr_id);
   7091 }
   7092 
   7093 bool ImGui::IsRectVisible(const ImVec2& size)
   7094 {
   7095     ImGuiWindow* window = GImGui->CurrentWindow;
   7096     return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
   7097 }
   7098 
   7099 bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
   7100 {
   7101     ImGuiWindow* window = GImGui->CurrentWindow;
   7102     return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
   7103 }
   7104 
   7105 
   7106 //-----------------------------------------------------------------------------
   7107 // [SECTION] ERROR CHECKING
   7108 //-----------------------------------------------------------------------------
   7109 
   7110 // Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
   7111 // Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
   7112 // If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
   7113 // may see different structures than what imgui.cpp sees, which is problematic.
   7114 // We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui.
   7115 bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
   7116 {
   7117     bool error = false;
   7118     if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); }
   7119     if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
   7120     if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
   7121     if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
   7122     if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
   7123     if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
   7124     if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); }
   7125     return !error;
   7126 }
   7127 
   7128 static void ImGui::ErrorCheckNewFrameSanityChecks()
   7129 {
   7130     ImGuiContext& g = *GImGui;
   7131 
   7132     // Check user IM_ASSERT macro
   7133     // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means your assert macro is incorrectly defined!
   7134     //  If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block.
   7135     //  This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.)
   7136     // #define IM_ASSERT(EXPR)   if (SomeCode(EXPR)) SomeMoreCode();                    // Wrong!
   7137     // #define IM_ASSERT(EXPR)   do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0)   // Correct!
   7138     if (true) IM_ASSERT(1); else IM_ASSERT(0);
   7139 
   7140     // Check user data
   7141     // (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)
   7142     IM_ASSERT(g.Initialized);
   7143     IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0)              && "Need a positive DeltaTime!");
   7144     IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount)  && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
   7145     IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f  && "Invalid DisplaySize value!");
   7146     IM_ASSERT(g.IO.Fonts->Fonts.Size > 0                                && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?");
   7147     IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()                          && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()?");
   7148     IM_ASSERT(g.Style.CurveTessellationTol > 0.0f                       && "Invalid style setting!");
   7149     IM_ASSERT(g.Style.CircleTessellationMaxError  > 0.0f                && "Invalid style setting!");
   7150     IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f            && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations
   7151     IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
   7152     IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
   7153     for (int n = 0; n < ImGuiKey_COUNT; n++)
   7154         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)");
   7155 
   7156     // 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 added in 1.60 WIP)
   7157     if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
   7158         IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
   7159 
   7160     // Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
   7161     if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
   7162         g.IO.ConfigWindowsResizeFromEdges = false;
   7163 }
   7164 
   7165 static void ImGui::ErrorCheckEndFrameSanityChecks()
   7166 {
   7167     ImGuiContext& g = *GImGui;
   7168 
   7169     // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame()
   7170     // One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame().
   7171     // It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will
   7172     // send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs.
   7173     // We silently accommodate for this case by ignoring/ the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0),
   7174     // while still correctly asserting on mid-frame key press events.
   7175     const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags();
   7176     IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
   7177     IM_UNUSED(key_mod_flags);
   7178 
   7179     // Recover from errors
   7180     //ErrorCheckEndFrameRecover();
   7181 
   7182     // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
   7183     // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
   7184     if (g.CurrentWindowStack.Size != 1)
   7185     {
   7186         if (g.CurrentWindowStack.Size > 1)
   7187         {
   7188             IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
   7189             while (g.CurrentWindowStack.Size > 1)
   7190                 End();
   7191         }
   7192         else
   7193         {
   7194             IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
   7195         }
   7196     }
   7197 
   7198     IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!");
   7199 }
   7200 
   7201 // Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls.
   7202 // Must be called during or before EndFrame().
   7203 // This is generally flawed as we are not necessarily End/Popping things in the right order.
   7204 // FIXME: Can't recover from inside BeginTabItem/EndTabItem yet.
   7205 // FIXME: Can't recover from interleaved BeginTabBar/Begin
   7206 void    ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data)
   7207 {
   7208     // PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations"
   7209     ImGuiContext& g = *GImGui;
   7210     while (g.CurrentWindowStack.Size > 0)
   7211     {
   7212         while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow))
   7213         {
   7214             if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name);
   7215             EndTable();
   7216         }
   7217         ImGuiWindow* window = g.CurrentWindow;
   7218         IM_ASSERT(window != NULL);
   7219         while (g.CurrentTabBar != NULL) //-V1044
   7220         {
   7221             if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name);
   7222             EndTabBar();
   7223         }
   7224         while (window->DC.TreeDepth > 0)
   7225         {
   7226             if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name);
   7227             TreePop();
   7228         }
   7229         while (g.GroupStack.Size > window->DC.StackSizesOnBegin.SizeOfGroupStack)
   7230         {
   7231             if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name);
   7232             EndGroup();
   7233         }
   7234         while (window->IDStack.Size > 1)
   7235         {
   7236             if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name);
   7237             PopID();
   7238         }
   7239         while (g.ColorStack.Size > window->DC.StackSizesOnBegin.SizeOfColorStack)
   7240         {
   7241             if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col));
   7242             PopStyleColor();
   7243         }
   7244         while (g.StyleVarStack.Size > window->DC.StackSizesOnBegin.SizeOfStyleVarStack)
   7245         {
   7246             if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name);
   7247             PopStyleVar();
   7248         }
   7249         while (g.FocusScopeStack.Size > window->DC.StackSizesOnBegin.SizeOfFocusScopeStack)
   7250         {
   7251             if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name);
   7252             PopFocusScope();
   7253         }
   7254         if (g.CurrentWindowStack.Size == 1)
   7255         {
   7256             IM_ASSERT(g.CurrentWindow->IsFallbackWindow);
   7257             break;
   7258         }
   7259         IM_ASSERT(window == g.CurrentWindow);
   7260         if (window->Flags & ImGuiWindowFlags_ChildWindow)
   7261         {
   7262             if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name);
   7263             EndChild();
   7264         }
   7265         else
   7266         {
   7267             if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name);
   7268             End();
   7269         }
   7270     }
   7271 }
   7272 
   7273 // Save current stack sizes for later compare
   7274 void ImGuiStackSizes::SetToCurrentState()
   7275 {
   7276     ImGuiContext& g = *GImGui;
   7277     ImGuiWindow* window = g.CurrentWindow;
   7278     SizeOfIDStack = (short)window->IDStack.Size;
   7279     SizeOfColorStack = (short)g.ColorStack.Size;
   7280     SizeOfStyleVarStack = (short)g.StyleVarStack.Size;
   7281     SizeOfFontStack = (short)g.FontStack.Size;
   7282     SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size;
   7283     SizeOfGroupStack = (short)g.GroupStack.Size;
   7284     SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size;
   7285 }
   7286 
   7287 // Compare to detect usage errors
   7288 void ImGuiStackSizes::CompareWithCurrentState()
   7289 {
   7290     ImGuiContext& g = *GImGui;
   7291     ImGuiWindow* window = g.CurrentWindow;
   7292     IM_UNUSED(window);
   7293 
   7294     // Window stacks
   7295     // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
   7296     IM_ASSERT(SizeOfIDStack         == window->IDStack.Size     && "PushID/PopID or TreeNode/TreePop Mismatch!");
   7297 
   7298     // Global stacks
   7299     // 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.
   7300     IM_ASSERT(SizeOfGroupStack      == g.GroupStack.Size        && "BeginGroup/EndGroup Mismatch!");
   7301     IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size   && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!");
   7302     IM_ASSERT(SizeOfColorStack      >= g.ColorStack.Size        && "PushStyleColor/PopStyleColor Mismatch!");
   7303     IM_ASSERT(SizeOfStyleVarStack   >= g.StyleVarStack.Size     && "PushStyleVar/PopStyleVar Mismatch!");
   7304     IM_ASSERT(SizeOfFontStack       >= g.FontStack.Size         && "PushFont/PopFont Mismatch!");
   7305     IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size   && "PushFocusScope/PopFocusScope Mismatch!");
   7306 }
   7307 
   7308 
   7309 //-----------------------------------------------------------------------------
   7310 // [SECTION] LAYOUT
   7311 //-----------------------------------------------------------------------------
   7312 // - ItemSize()
   7313 // - ItemAdd()
   7314 // - SameLine()
   7315 // - GetCursorScreenPos()
   7316 // - SetCursorScreenPos()
   7317 // - GetCursorPos(), GetCursorPosX(), GetCursorPosY()
   7318 // - SetCursorPos(), SetCursorPosX(), SetCursorPosY()
   7319 // - GetCursorStartPos()
   7320 // - Indent()
   7321 // - Unindent()
   7322 // - SetNextItemWidth()
   7323 // - PushItemWidth()
   7324 // - PushMultiItemsWidths()
   7325 // - PopItemWidth()
   7326 // - CalcItemWidth()
   7327 // - CalcItemSize()
   7328 // - GetTextLineHeight()
   7329 // - GetTextLineHeightWithSpacing()
   7330 // - GetFrameHeight()
   7331 // - GetFrameHeightWithSpacing()
   7332 // - GetContentRegionMax()
   7333 // - GetContentRegionMaxAbs() [Internal]
   7334 // - GetContentRegionAvail(),
   7335 // - GetWindowContentRegionMin(), GetWindowContentRegionMax()
   7336 // - GetWindowContentRegionWidth()
   7337 // - BeginGroup()
   7338 // - EndGroup()
   7339 // Also see in imgui_widgets: tab bars, columns.
   7340 //-----------------------------------------------------------------------------
   7341 
   7342 // Advance cursor given item size for layout.
   7343 // Register minimum needed size so it can extend the bounding box used for auto-fit calculation.
   7344 // See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.
   7345 void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
   7346 {
   7347     ImGuiContext& g = *GImGui;
   7348     ImGuiWindow* window = g.CurrentWindow;
   7349     if (window->SkipItems)
   7350         return;
   7351 
   7352     // We increase the height in this function to accommodate for baseline offset.
   7353     // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
   7354     // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
   7355     const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
   7356     const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y);
   7357 
   7358     // Always align ourselves on pixel boundaries
   7359     //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]
   7360     window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
   7361     window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
   7362     window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);    // Next line
   7363     window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);        // Next line
   7364     window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
   7365     window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
   7366     //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
   7367 
   7368     window->DC.PrevLineSize.y = line_height;
   7369     window->DC.CurrLineSize.y = 0.0f;
   7370     window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
   7371     window->DC.CurrLineTextBaseOffset = 0.0f;
   7372 
   7373     // Horizontal layout mode
   7374     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
   7375         SameLine();
   7376 }
   7377 
   7378 void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
   7379 {
   7380     ItemSize(bb.GetSize(), text_baseline_y);
   7381 }
   7382 
   7383 // Declare item bounding box for clipping and interaction.
   7384 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
   7385 // declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
   7386 bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemAddFlags flags)
   7387 {
   7388     ImGuiContext& g = *GImGui;
   7389     ImGuiWindow* window = g.CurrentWindow;
   7390 
   7391     if (id != 0)
   7392     {
   7393         // Navigation processing runs prior to clipping early-out
   7394         //  (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
   7395         //  (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
   7396         //      unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
   7397         //      thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
   7398         //      We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
   7399         //      to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
   7400         // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
   7401         // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
   7402         window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
   7403         if (g.NavId == id || g.NavAnyRequest)
   7404             if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
   7405                 if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
   7406                     NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
   7407 
   7408         // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
   7409 #ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
   7410         if (id == g.DebugItemPickerBreakId)
   7411         {
   7412             IM_DEBUG_BREAK();
   7413             g.DebugItemPickerBreakId = 0;
   7414         }
   7415 #endif
   7416     }
   7417 
   7418     // Equivalent to calling SetLastItemData()
   7419     window->DC.LastItemId = id;
   7420     window->DC.LastItemRect = bb;
   7421     window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
   7422     g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
   7423 
   7424 #ifdef IMGUI_ENABLE_TEST_ENGINE
   7425     if (id != 0)
   7426         IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id);
   7427 #endif
   7428 
   7429     // Clipping test
   7430     const bool is_clipped = IsClippedEx(bb, id, false);
   7431     if (is_clipped)
   7432         return false;
   7433     //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
   7434 
   7435     // Tab stop handling (previously was using internal ItemFocusable() api)
   7436     // FIXME-NAV: We would now want to move this above the clipping test, but this would require being able to scroll and currently this would mean an extra frame. (#4079, #343)
   7437     if (flags & ImGuiItemAddFlags_Focusable)
   7438         ItemFocusable(window, id);
   7439 
   7440     // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
   7441     if (IsMouseHoveringRect(bb.Min, bb.Max))
   7442         window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
   7443     return true;
   7444 }
   7445 
   7446 // Gets back to previous line and continue with horizontal layout
   7447 //      offset_from_start_x == 0 : follow right after previous item
   7448 //      offset_from_start_x != 0 : align to specified x position (relative to window/group left)
   7449 //      spacing_w < 0            : use default spacing if pos_x == 0, no spacing if pos_x != 0
   7450 //      spacing_w >= 0           : enforce spacing amount
   7451 void ImGui::SameLine(float offset_from_start_x, float spacing_w)
   7452 {
   7453     ImGuiWindow* window = GetCurrentWindow();
   7454     if (window->SkipItems)
   7455         return;
   7456 
   7457     ImGuiContext& g = *GImGui;
   7458     if (offset_from_start_x != 0.0f)
   7459     {
   7460         if (spacing_w < 0.0f) spacing_w = 0.0f;
   7461         window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
   7462         window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
   7463     }
   7464     else
   7465     {
   7466         if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
   7467         window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
   7468         window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
   7469     }
   7470     window->DC.CurrLineSize = window->DC.PrevLineSize;
   7471     window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
   7472 }
   7473 
   7474 ImVec2 ImGui::GetCursorScreenPos()
   7475 {
   7476     ImGuiWindow* window = GetCurrentWindowRead();
   7477     return window->DC.CursorPos;
   7478 }
   7479 
   7480 void ImGui::SetCursorScreenPos(const ImVec2& pos)
   7481 {
   7482     ImGuiWindow* window = GetCurrentWindow();
   7483     window->DC.CursorPos = pos;
   7484     window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
   7485 }
   7486 
   7487 // User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
   7488 // 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'.
   7489 ImVec2 ImGui::GetCursorPos()
   7490 {
   7491     ImGuiWindow* window = GetCurrentWindowRead();
   7492     return window->DC.CursorPos - window->Pos + window->Scroll;
   7493 }
   7494 
   7495 float ImGui::GetCursorPosX()
   7496 {
   7497     ImGuiWindow* window = GetCurrentWindowRead();
   7498     return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
   7499 }
   7500 
   7501 float ImGui::GetCursorPosY()
   7502 {
   7503     ImGuiWindow* window = GetCurrentWindowRead();
   7504     return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
   7505 }
   7506 
   7507 void ImGui::SetCursorPos(const ImVec2& local_pos)
   7508 {
   7509     ImGuiWindow* window = GetCurrentWindow();
   7510     window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
   7511     window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
   7512 }
   7513 
   7514 void ImGui::SetCursorPosX(float x)
   7515 {
   7516     ImGuiWindow* window = GetCurrentWindow();
   7517     window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
   7518     window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
   7519 }
   7520 
   7521 void ImGui::SetCursorPosY(float y)
   7522 {
   7523     ImGuiWindow* window = GetCurrentWindow();
   7524     window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
   7525     window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
   7526 }
   7527 
   7528 ImVec2 ImGui::GetCursorStartPos()
   7529 {
   7530     ImGuiWindow* window = GetCurrentWindowRead();
   7531     return window->DC.CursorStartPos - window->Pos;
   7532 }
   7533 
   7534 void ImGui::Indent(float indent_w)
   7535 {
   7536     ImGuiContext& g = *GImGui;
   7537     ImGuiWindow* window = GetCurrentWindow();
   7538     window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
   7539     window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
   7540 }
   7541 
   7542 void ImGui::Unindent(float indent_w)
   7543 {
   7544     ImGuiContext& g = *GImGui;
   7545     ImGuiWindow* window = GetCurrentWindow();
   7546     window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
   7547     window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
   7548 }
   7549 
   7550 // Affect large frame+labels widgets only.
   7551 void ImGui::SetNextItemWidth(float item_width)
   7552 {
   7553     ImGuiContext& g = *GImGui;
   7554     g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
   7555     g.NextItemData.Width = item_width;
   7556 }
   7557 
   7558 // FIXME: Remove the == 0.0f behavior?
   7559 void ImGui::PushItemWidth(float item_width)
   7560 {
   7561     ImGuiContext& g = *GImGui;
   7562     ImGuiWindow* window = g.CurrentWindow;
   7563     window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width
   7564     window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
   7565     g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
   7566 }
   7567 
   7568 void ImGui::PushMultiItemsWidths(int components, float w_full)
   7569 {
   7570     ImGuiContext& g = *GImGui;
   7571     ImGuiWindow* window = g.CurrentWindow;
   7572     const ImGuiStyle& style = g.Style;
   7573     const float w_item_one  = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));
   7574     const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));
   7575     window->DC.ItemWidthStack.push_back(window->DC.ItemWidth); // Backup current width
   7576     window->DC.ItemWidthStack.push_back(w_item_last);
   7577     for (int i = 0; i < components - 2; i++)
   7578         window->DC.ItemWidthStack.push_back(w_item_one);
   7579     window->DC.ItemWidth = (components == 1) ? w_item_last : w_item_one;
   7580     g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
   7581 }
   7582 
   7583 void ImGui::PopItemWidth()
   7584 {
   7585     ImGuiWindow* window = GetCurrentWindow();
   7586     window->DC.ItemWidth = window->DC.ItemWidthStack.back();
   7587     window->DC.ItemWidthStack.pop_back();
   7588 }
   7589 
   7590 // Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
   7591 // The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
   7592 float ImGui::CalcItemWidth()
   7593 {
   7594     ImGuiContext& g = *GImGui;
   7595     ImGuiWindow* window = g.CurrentWindow;
   7596     float w;
   7597     if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
   7598         w = g.NextItemData.Width;
   7599     else
   7600         w = window->DC.ItemWidth;
   7601     if (w < 0.0f)
   7602     {
   7603         float region_max_x = GetContentRegionMaxAbs().x;
   7604         w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
   7605     }
   7606     w = IM_FLOOR(w);
   7607     return w;
   7608 }
   7609 
   7610 // [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
   7611 // Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
   7612 // Note that only CalcItemWidth() is publicly exposed.
   7613 // The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
   7614 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
   7615 {
   7616     ImGuiWindow* window = GImGui->CurrentWindow;
   7617 
   7618     ImVec2 region_max;
   7619     if (size.x < 0.0f || size.y < 0.0f)
   7620         region_max = GetContentRegionMaxAbs();
   7621 
   7622     if (size.x == 0.0f)
   7623         size.x = default_w;
   7624     else if (size.x < 0.0f)
   7625         size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
   7626 
   7627     if (size.y == 0.0f)
   7628         size.y = default_h;
   7629     else if (size.y < 0.0f)
   7630         size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
   7631 
   7632     return size;
   7633 }
   7634 
   7635 float ImGui::GetTextLineHeight()
   7636 {
   7637     ImGuiContext& g = *GImGui;
   7638     return g.FontSize;
   7639 }
   7640 
   7641 float ImGui::GetTextLineHeightWithSpacing()
   7642 {
   7643     ImGuiContext& g = *GImGui;
   7644     return g.FontSize + g.Style.ItemSpacing.y;
   7645 }
   7646 
   7647 float ImGui::GetFrameHeight()
   7648 {
   7649     ImGuiContext& g = *GImGui;
   7650     return g.FontSize + g.Style.FramePadding.y * 2.0f;
   7651 }
   7652 
   7653 float ImGui::GetFrameHeightWithSpacing()
   7654 {
   7655     ImGuiContext& g = *GImGui;
   7656     return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
   7657 }
   7658 
   7659 // 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!
   7660 
   7661 // FIXME: This is in window space (not screen space!).
   7662 ImVec2 ImGui::GetContentRegionMax()
   7663 {
   7664     ImGuiContext& g = *GImGui;
   7665     ImGuiWindow* window = g.CurrentWindow;
   7666     ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
   7667     if (window->DC.CurrentColumns || g.CurrentTable)
   7668         mx.x = window->WorkRect.Max.x - window->Pos.x;
   7669     return mx;
   7670 }
   7671 
   7672 // [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
   7673 ImVec2 ImGui::GetContentRegionMaxAbs()
   7674 {
   7675     ImGuiContext& g = *GImGui;
   7676     ImGuiWindow* window = g.CurrentWindow;
   7677     ImVec2 mx = window->ContentRegionRect.Max;
   7678     if (window->DC.CurrentColumns || g.CurrentTable)
   7679         mx.x = window->WorkRect.Max.x;
   7680     return mx;
   7681 }
   7682 
   7683 ImVec2 ImGui::GetContentRegionAvail()
   7684 {
   7685     ImGuiWindow* window = GImGui->CurrentWindow;
   7686     return GetContentRegionMaxAbs() - window->DC.CursorPos;
   7687 }
   7688 
   7689 // In window space (not screen space!)
   7690 ImVec2 ImGui::GetWindowContentRegionMin()
   7691 {
   7692     ImGuiWindow* window = GImGui->CurrentWindow;
   7693     return window->ContentRegionRect.Min - window->Pos;
   7694 }
   7695 
   7696 ImVec2 ImGui::GetWindowContentRegionMax()
   7697 {
   7698     ImGuiWindow* window = GImGui->CurrentWindow;
   7699     return window->ContentRegionRect.Max - window->Pos;
   7700 }
   7701 
   7702 float ImGui::GetWindowContentRegionWidth()
   7703 {
   7704     ImGuiWindow* window = GImGui->CurrentWindow;
   7705     return window->ContentRegionRect.GetWidth();
   7706 }
   7707 
   7708 // 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.)
   7709 // Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
   7710 void ImGui::BeginGroup()
   7711 {
   7712     ImGuiContext& g = *GImGui;
   7713     ImGuiWindow* window = g.CurrentWindow;
   7714 
   7715     g.GroupStack.resize(g.GroupStack.Size + 1);
   7716     ImGuiGroupData& group_data = g.GroupStack.back();
   7717     group_data.WindowID = window->ID;
   7718     group_data.BackupCursorPos = window->DC.CursorPos;
   7719     group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
   7720     group_data.BackupIndent = window->DC.Indent;
   7721     group_data.BackupGroupOffset = window->DC.GroupOffset;
   7722     group_data.BackupCurrLineSize = window->DC.CurrLineSize;
   7723     group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
   7724     group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
   7725     group_data.BackupHoveredIdIsAlive = g.HoveredId != 0;
   7726     group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
   7727     group_data.EmitItem = true;
   7728 
   7729     window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
   7730     window->DC.Indent = window->DC.GroupOffset;
   7731     window->DC.CursorMaxPos = window->DC.CursorPos;
   7732     window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
   7733     if (g.LogEnabled)
   7734         g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
   7735 }
   7736 
   7737 void ImGui::EndGroup()
   7738 {
   7739     ImGuiContext& g = *GImGui;
   7740     ImGuiWindow* window = g.CurrentWindow;
   7741     IM_ASSERT(g.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls
   7742 
   7743     ImGuiGroupData& group_data = g.GroupStack.back();
   7744     IM_ASSERT(group_data.WindowID == window->ID); // EndGroup() in wrong window?
   7745 
   7746     ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
   7747 
   7748     window->DC.CursorPos = group_data.BackupCursorPos;
   7749     window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
   7750     window->DC.Indent = group_data.BackupIndent;
   7751     window->DC.GroupOffset = group_data.BackupGroupOffset;
   7752     window->DC.CurrLineSize = group_data.BackupCurrLineSize;
   7753     window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
   7754     if (g.LogEnabled)
   7755         g.LogLinePosY = -FLT_MAX; // To enforce a carriage return
   7756 
   7757     if (!group_data.EmitItem)
   7758     {
   7759         g.GroupStack.pop_back();
   7760         return;
   7761     }
   7762 
   7763     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.
   7764     ItemSize(group_bb.GetSize());
   7765     ItemAdd(group_bb, 0);
   7766 
   7767     // 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.
   7768     // 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.
   7769     // Also if you grep for LastItemId you'll notice it is only used in that context.
   7770     // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
   7771     const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
   7772     const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);
   7773     if (group_contains_curr_active_id)
   7774         window->DC.LastItemId = g.ActiveId;
   7775     else if (group_contains_prev_active_id)
   7776         window->DC.LastItemId = g.ActiveIdPreviousFrame;
   7777     window->DC.LastItemRect = group_bb;
   7778 
   7779     // Forward Hovered flag
   7780     const bool group_contains_curr_hovered_id = (group_data.BackupHoveredIdIsAlive == false) && g.HoveredId != 0;
   7781     if (group_contains_curr_hovered_id)
   7782         window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
   7783 
   7784     // Forward Edited flag
   7785     if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
   7786         window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
   7787 
   7788     // Forward Deactivated flag
   7789     window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
   7790     if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
   7791         window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
   7792 
   7793     g.GroupStack.pop_back();
   7794     //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255));   // [Debug]
   7795 }
   7796 
   7797 
   7798 //-----------------------------------------------------------------------------
   7799 // [SECTION] SCROLLING
   7800 //-----------------------------------------------------------------------------
   7801 
   7802 // Helper to snap on edges when aiming at an item very close to the edge,
   7803 // So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling.
   7804 // When we refactor the scrolling API this may be configurable with a flag?
   7805 // Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default.
   7806 static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
   7807 {
   7808     if (target <= snap_min + snap_threshold)
   7809         return ImLerp(snap_min, target, center_ratio);
   7810     if (target >= snap_max - snap_threshold)
   7811         return ImLerp(target, snap_max, center_ratio);
   7812     return target;
   7813 }
   7814 
   7815 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
   7816 {
   7817     ImVec2 scroll = window->Scroll;
   7818     if (window->ScrollTarget.x < FLT_MAX)
   7819     {
   7820         float decoration_total_width = window->ScrollbarSizes.x;
   7821         float center_x_ratio = window->ScrollTargetCenterRatio.x;
   7822         float scroll_target_x = window->ScrollTarget.x;
   7823         if (window->ScrollTargetEdgeSnapDist.x > 0.0f)
   7824         {
   7825             float snap_x_min = 0.0f;
   7826             float snap_x_max = window->ScrollMax.x + window->SizeFull.x - decoration_total_width;
   7827             scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio);
   7828         }
   7829         scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - decoration_total_width);
   7830     }
   7831     if (window->ScrollTarget.y < FLT_MAX)
   7832     {
   7833         float decoration_total_height = window->TitleBarHeight() + window->MenuBarHeight() + window->ScrollbarSizes.y;
   7834         float center_y_ratio = window->ScrollTargetCenterRatio.y;
   7835         float scroll_target_y = window->ScrollTarget.y;
   7836         if (window->ScrollTargetEdgeSnapDist.y > 0.0f)
   7837         {
   7838             float snap_y_min = 0.0f;
   7839             float snap_y_max = window->ScrollMax.y + window->SizeFull.y - decoration_total_height;
   7840             scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio);
   7841         }
   7842         scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - decoration_total_height);
   7843     }
   7844     scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f));
   7845     scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f));
   7846     if (!window->Collapsed && !window->SkipItems)
   7847     {
   7848         scroll.x = ImMin(scroll.x, window->ScrollMax.x);
   7849         scroll.y = ImMin(scroll.y, window->ScrollMax.y);
   7850     }
   7851     return scroll;
   7852 }
   7853 
   7854 // Scroll to keep newly navigated item fully into view
   7855 ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
   7856 {
   7857     ImGuiContext& g = *GImGui;
   7858     ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
   7859     //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
   7860 
   7861     ImVec2 delta_scroll;
   7862     if (!window_rect.Contains(item_rect))
   7863     {
   7864         if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
   7865             SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x - g.Style.ItemSpacing.x, 0.0f);
   7866         else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
   7867             SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
   7868         if (item_rect.Min.y < window_rect.Min.y)
   7869             SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
   7870         else if (item_rect.Max.y >= window_rect.Max.y)
   7871             SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
   7872 
   7873         ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
   7874         delta_scroll = next_scroll - window->Scroll;
   7875     }
   7876 
   7877     // Also scroll parent window to keep us into view if necessary
   7878     if (window->Flags & ImGuiWindowFlags_ChildWindow)
   7879         delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll));
   7880 
   7881     return delta_scroll;
   7882 }
   7883 
   7884 float ImGui::GetScrollX()
   7885 {
   7886     ImGuiWindow* window = GImGui->CurrentWindow;
   7887     return window->Scroll.x;
   7888 }
   7889 
   7890 float ImGui::GetScrollY()
   7891 {
   7892     ImGuiWindow* window = GImGui->CurrentWindow;
   7893     return window->Scroll.y;
   7894 }
   7895 
   7896 float ImGui::GetScrollMaxX()
   7897 {
   7898     ImGuiWindow* window = GImGui->CurrentWindow;
   7899     return window->ScrollMax.x;
   7900 }
   7901 
   7902 float ImGui::GetScrollMaxY()
   7903 {
   7904     ImGuiWindow* window = GImGui->CurrentWindow;
   7905     return window->ScrollMax.y;
   7906 }
   7907 
   7908 void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x)
   7909 {
   7910     window->ScrollTarget.x = scroll_x;
   7911     window->ScrollTargetCenterRatio.x = 0.0f;
   7912     window->ScrollTargetEdgeSnapDist.x = 0.0f;
   7913 }
   7914 
   7915 void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y)
   7916 {
   7917     window->ScrollTarget.y = scroll_y;
   7918     window->ScrollTargetCenterRatio.y = 0.0f;
   7919     window->ScrollTargetEdgeSnapDist.y = 0.0f;
   7920 }
   7921 
   7922 void ImGui::SetScrollX(float scroll_x)
   7923 {
   7924     ImGuiContext& g = *GImGui;
   7925     SetScrollX(g.CurrentWindow, scroll_x);
   7926 }
   7927 
   7928 void ImGui::SetScrollY(float scroll_y)
   7929 {
   7930     ImGuiContext& g = *GImGui;
   7931     SetScrollY(g.CurrentWindow, scroll_y);
   7932 }
   7933 
   7934 // Note that a local position will vary depending on initial scroll value,
   7935 // This is a little bit confusing so bear with us:
   7936 //  - local_pos = (absolution_pos - window->Pos)
   7937 //  - So local_x/local_y are 0.0f for a position at the upper-left corner of a window,
   7938 //    and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area.
   7939 //  - They mostly exists because of legacy API.
   7940 // Following the rules above, when trying to work with scrolling code, consider that:
   7941 //  - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect!
   7942 //  - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense
   7943 // We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size
   7944 void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
   7945 {
   7946     IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
   7947     window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); // Convert local position to scroll offset
   7948     window->ScrollTargetCenterRatio.x = center_x_ratio;
   7949     window->ScrollTargetEdgeSnapDist.x = 0.0f;
   7950 }
   7951 
   7952 void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
   7953 {
   7954     IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
   7955     const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect;
   7956     local_y -= decoration_up_height;
   7957     window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset
   7958     window->ScrollTargetCenterRatio.y = center_y_ratio;
   7959     window->ScrollTargetEdgeSnapDist.y = 0.0f;
   7960 }
   7961 
   7962 void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
   7963 {
   7964     ImGuiContext& g = *GImGui;
   7965     SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);
   7966 }
   7967 
   7968 void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
   7969 {
   7970     ImGuiContext& g = *GImGui;
   7971     SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);
   7972 }
   7973 
   7974 // center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
   7975 void ImGui::SetScrollHereX(float center_x_ratio)
   7976 {
   7977     ImGuiContext& g = *GImGui;
   7978     ImGuiWindow* window = g.CurrentWindow;
   7979     float spacing_x = ImMax(window->WindowPadding.x, g.Style.ItemSpacing.x);
   7980     float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio);
   7981     SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
   7982 
   7983     // Tweak: snap on edges when aiming at an item very close to the edge
   7984     window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x);
   7985 }
   7986 
   7987 // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
   7988 void ImGui::SetScrollHereY(float center_y_ratio)
   7989 {
   7990     ImGuiContext& g = *GImGui;
   7991     ImGuiWindow* window = g.CurrentWindow;
   7992     float spacing_y = ImMax(window->WindowPadding.y, g.Style.ItemSpacing.y);
   7993     float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
   7994     SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos
   7995 
   7996     // Tweak: snap on edges when aiming at an item very close to the edge
   7997     window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y);
   7998 }
   7999 
   8000 //-----------------------------------------------------------------------------
   8001 // [SECTION] TOOLTIPS
   8002 //-----------------------------------------------------------------------------
   8003 
   8004 void ImGui::BeginTooltip()
   8005 {
   8006     BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None);
   8007 }
   8008 
   8009 void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags)
   8010 {
   8011     ImGuiContext& g = *GImGui;
   8012 
   8013     if (g.DragDropWithinSource || g.DragDropWithinTarget)
   8014     {
   8015         // 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)
   8016         // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor.
   8017         // 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.
   8018         //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;
   8019         ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale);
   8020         SetNextWindowPos(tooltip_pos);
   8021         SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f);
   8022         //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(
   8023         tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip;
   8024     }
   8025 
   8026     char window_name[16];
   8027     ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
   8028     if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip)
   8029         if (ImGuiWindow* window = FindWindowByName(window_name))
   8030             if (window->Active)
   8031             {
   8032                 // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
   8033                 window->Hidden = true;
   8034                 window->HiddenFramesCanSkipItems = 1; // FIXME: This may not be necessary?
   8035                 ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
   8036             }
   8037     ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize;
   8038     Begin(window_name, NULL, flags | extra_flags);
   8039 }
   8040 
   8041 void ImGui::EndTooltip()
   8042 {
   8043     IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip);   // Mismatched BeginTooltip()/EndTooltip() calls
   8044     End();
   8045 }
   8046 
   8047 void ImGui::SetTooltipV(const char* fmt, va_list args)
   8048 {
   8049     BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip);
   8050     TextV(fmt, args);
   8051     EndTooltip();
   8052 }
   8053 
   8054 void ImGui::SetTooltip(const char* fmt, ...)
   8055 {
   8056     va_list args;
   8057     va_start(args, fmt);
   8058     SetTooltipV(fmt, args);
   8059     va_end(args);
   8060 }
   8061 
   8062 //-----------------------------------------------------------------------------
   8063 // [SECTION] POPUPS
   8064 //-----------------------------------------------------------------------------
   8065 
   8066 // Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel
   8067 bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags)
   8068 {
   8069     ImGuiContext& g = *GImGui;
   8070     if (popup_flags & ImGuiPopupFlags_AnyPopupId)
   8071     {
   8072         // Return true if any popup is open at the current BeginPopup() level of the popup stack
   8073         // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level.
   8074         IM_ASSERT(id == 0);
   8075         if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
   8076             return g.OpenPopupStack.Size > 0;
   8077         else
   8078             return g.OpenPopupStack.Size > g.BeginPopupStack.Size;
   8079     }
   8080     else
   8081     {
   8082         if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
   8083         {
   8084             // Return true if the popup is open anywhere in the popup stack
   8085             for (int n = 0; n < g.OpenPopupStack.Size; n++)
   8086                 if (g.OpenPopupStack[n].PopupId == id)
   8087                     return true;
   8088             return false;
   8089         }
   8090         else
   8091         {
   8092             // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query)
   8093             return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
   8094         }
   8095     }
   8096 }
   8097 
   8098 bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)
   8099 {
   8100     ImGuiContext& g = *GImGui;
   8101     ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id);
   8102     if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0)
   8103         IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally
   8104     return IsPopupOpen(id, popup_flags);
   8105 }
   8106 
   8107 ImGuiWindow* ImGui::GetTopMostPopupModal()
   8108 {
   8109     ImGuiContext& g = *GImGui;
   8110     for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
   8111         if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
   8112             if (popup->Flags & ImGuiWindowFlags_Modal)
   8113                 return popup;
   8114     return NULL;
   8115 }
   8116 
   8117 void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
   8118 {
   8119     ImGuiContext& g = *GImGui;
   8120     OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags);
   8121 }
   8122 
   8123 void ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags)
   8124 {
   8125     OpenPopupEx(id, popup_flags);
   8126 }
   8127 
   8128 // Mark popup as open (toggle toward open state).
   8129 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
   8130 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
   8131 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
   8132 void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
   8133 {
   8134     ImGuiContext& g = *GImGui;
   8135     ImGuiWindow* parent_window = g.CurrentWindow;
   8136     const int current_stack_size = g.BeginPopupStack.Size;
   8137 
   8138     if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup)
   8139         if (IsPopupOpen(0u, ImGuiPopupFlags_AnyPopupId))
   8140             return;
   8141 
   8142     ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
   8143     popup_ref.PopupId = id;
   8144     popup_ref.Window = NULL;
   8145     popup_ref.SourceWindow = g.NavWindow;
   8146     popup_ref.OpenFrameCount = g.FrameCount;
   8147     popup_ref.OpenParentId = parent_window->IDStack.back();
   8148     popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
   8149     popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
   8150 
   8151     IMGUI_DEBUG_LOG_POPUP("OpenPopupEx(0x%08X)\n", id);
   8152     if (g.OpenPopupStack.Size < current_stack_size + 1)
   8153     {
   8154         g.OpenPopupStack.push_back(popup_ref);
   8155     }
   8156     else
   8157     {
   8158         // 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
   8159         // 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
   8160         // 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.
   8161         if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
   8162         {
   8163             g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
   8164         }
   8165         else
   8166         {
   8167             // Close child popups if any, then flag popup for open/reopen
   8168             ClosePopupToLevel(current_stack_size, false);
   8169             g.OpenPopupStack.push_back(popup_ref);
   8170         }
   8171 
   8172         // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
   8173         // This is equivalent to what ClosePopupToLevel() does.
   8174         //if (g.OpenPopupStack[current_stack_size].PopupId == id)
   8175         //    FocusWindow(parent_window);
   8176     }
   8177 }
   8178 
   8179 // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
   8180 // This function closes any popups that are over 'ref_window'.
   8181 void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
   8182 {
   8183     ImGuiContext& g = *GImGui;
   8184     if (g.OpenPopupStack.Size == 0)
   8185         return;
   8186 
   8187     // Don't close our own child popup windows.
   8188     int popup_count_to_keep = 0;
   8189     if (ref_window)
   8190     {
   8191         // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
   8192         for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
   8193         {
   8194             ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep];
   8195             if (!popup.Window)
   8196                 continue;
   8197             IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
   8198             if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
   8199                 continue;
   8200 
   8201             // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow)
   8202             // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3:
   8203             //     Window -> Popup1 -> Popup2 -> Popup3
   8204             // - Each popups may contain child windows, which is why we compare ->RootWindow!
   8205             //     Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child
   8206             bool ref_window_is_descendent_of_popup = false;
   8207             for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
   8208                 if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
   8209                     if (popup_window->RootWindow == ref_window->RootWindow)
   8210                     {
   8211                         ref_window_is_descendent_of_popup = true;
   8212                         break;
   8213                     }
   8214             if (!ref_window_is_descendent_of_popup)
   8215                 break;
   8216         }
   8217     }
   8218     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
   8219     {
   8220         IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
   8221         ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);
   8222     }
   8223 }
   8224 
   8225 void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
   8226 {
   8227     ImGuiContext& g = *GImGui;
   8228     IMGUI_DEBUG_LOG_POPUP("ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup);
   8229     IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
   8230 
   8231     // Trim open popup stack
   8232     ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow;
   8233     ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;
   8234     g.OpenPopupStack.resize(remaining);
   8235 
   8236     if (restore_focus_to_window_under_popup)
   8237     {
   8238         if (focus_window && !focus_window->WasActive && popup_window)
   8239         {
   8240             // Fallback
   8241             FocusTopMostWindowUnderOne(popup_window, NULL);
   8242         }
   8243         else
   8244         {
   8245             if (g.NavLayer == ImGuiNavLayer_Main && focus_window)
   8246                 focus_window = NavRestoreLastChildNavWindow(focus_window);
   8247             FocusWindow(focus_window);
   8248         }
   8249     }
   8250 }
   8251 
   8252 // Close the popup we have begin-ed into.
   8253 void ImGui::CloseCurrentPopup()
   8254 {
   8255     ImGuiContext& g = *GImGui;
   8256     int popup_idx = g.BeginPopupStack.Size - 1;
   8257     if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
   8258         return;
   8259 
   8260     // Closing a menu closes its top-most parent popup (unless a modal)
   8261     while (popup_idx > 0)
   8262     {
   8263         ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
   8264         ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
   8265         bool close_parent = false;
   8266         if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
   8267             if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal))
   8268                 close_parent = true;
   8269         if (!close_parent)
   8270             break;
   8271         popup_idx--;
   8272     }
   8273     IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
   8274     ClosePopupToLevel(popup_idx, true);
   8275 
   8276     // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
   8277     // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
   8278     // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
   8279     if (ImGuiWindow* window = g.NavWindow)
   8280         window->DC.NavHideHighlightOneFrame = true;
   8281 }
   8282 
   8283 // Attention! BeginPopup() adds default flags which BeginPopupEx()!
   8284 bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
   8285 {
   8286     ImGuiContext& g = *GImGui;
   8287     if (!IsPopupOpen(id, ImGuiPopupFlags_None))
   8288     {
   8289         g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
   8290         return false;
   8291     }
   8292 
   8293     char name[20];
   8294     if (flags & ImGuiWindowFlags_ChildMenu)
   8295         ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
   8296     else
   8297         ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
   8298 
   8299     flags |= ImGuiWindowFlags_Popup;
   8300     bool is_open = Begin(name, NULL, flags);
   8301     if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
   8302         EndPopup();
   8303 
   8304     return is_open;
   8305 }
   8306 
   8307 bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
   8308 {
   8309     ImGuiContext& g = *GImGui;
   8310     if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
   8311     {
   8312         g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
   8313         return false;
   8314     }
   8315     flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
   8316     return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
   8317 }
   8318 
   8319 // If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
   8320 // 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.
   8321 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
   8322 {
   8323     ImGuiContext& g = *GImGui;
   8324     ImGuiWindow* window = g.CurrentWindow;
   8325     const ImGuiID id = window->GetID(name);
   8326     if (!IsPopupOpen(id, ImGuiPopupFlags_None))
   8327     {
   8328         g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
   8329         return false;
   8330     }
   8331 
   8332     // Center modal windows by default for increased visibility
   8333     // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves)
   8334     // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
   8335     if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
   8336     {
   8337         const ImGuiViewport* viewport = GetMainViewport();
   8338         SetNextWindowPos(viewport->GetCenter(), ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
   8339     }
   8340 
   8341     flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse;
   8342     const bool is_open = Begin(name, p_open, flags);
   8343     if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
   8344     {
   8345         EndPopup();
   8346         if (is_open)
   8347             ClosePopupToLevel(g.BeginPopupStack.Size, true);
   8348         return false;
   8349     }
   8350     return is_open;
   8351 }
   8352 
   8353 void ImGui::EndPopup()
   8354 {
   8355     ImGuiContext& g = *GImGui;
   8356     ImGuiWindow* window = g.CurrentWindow;
   8357     IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup);  // Mismatched BeginPopup()/EndPopup() calls
   8358     IM_ASSERT(g.BeginPopupStack.Size > 0);
   8359 
   8360     // Make all menus and popups wrap around for now, may need to expose that policy.
   8361     if (g.NavWindow == window)
   8362         NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
   8363 
   8364     // Child-popups don't need to be laid out
   8365     IM_ASSERT(g.WithinEndChild == false);
   8366     if (window->Flags & ImGuiWindowFlags_ChildWindow)
   8367         g.WithinEndChild = true;
   8368     End();
   8369     g.WithinEndChild = false;
   8370 }
   8371 
   8372 // Helper to open a popup if mouse button is released over the item
   8373 // - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()
   8374 void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)
   8375 {
   8376     ImGuiWindow* window = GImGui->CurrentWindow;
   8377     int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
   8378     if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
   8379     {
   8380         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!
   8381         IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
   8382         OpenPopupEx(id, popup_flags);
   8383     }
   8384 }
   8385 
   8386 // This is a helper to handle the simplest case of associating one named popup to one given widget.
   8387 // - To create a popup associated to the last item, you generally want to pass a NULL value to str_id.
   8388 // - To create a popup with a specific identifier, pass it in str_id.
   8389 //    - This is useful when using using BeginPopupContextItem() on an item which doesn't have an identifier, e.g. a Text() call.
   8390 //    - This is useful when multiple code locations may want to manipulate/open the same popup, given an explicit id.
   8391 // - You may want to handle the whole on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
   8392 //   This is essentially the same as:
   8393 //       id = str_id ? GetID(str_id) : GetItemID();
   8394 //       OpenPopupOnItemClick(str_id);
   8395 //       return BeginPopup(id);
   8396 //   Which is essentially the same as:
   8397 //       id = str_id ? GetID(str_id) : GetItemID();
   8398 //       if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
   8399 //           OpenPopup(id);
   8400 //       return BeginPopup(id);
   8401 //   The main difference being that this is tweaked to avoid computing the ID twice.
   8402 bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
   8403 {
   8404     ImGuiWindow* window = GImGui->CurrentWindow;
   8405     if (window->SkipItems)
   8406         return false;
   8407     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!
   8408     IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
   8409     int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
   8410     if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
   8411         OpenPopupEx(id, popup_flags);
   8412     return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
   8413 }
   8414 
   8415 bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
   8416 {
   8417     ImGuiWindow* window = GImGui->CurrentWindow;
   8418     if (!str_id)
   8419         str_id = "window_context";
   8420     ImGuiID id = window->GetID(str_id);
   8421     int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
   8422     if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
   8423         if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())
   8424             OpenPopupEx(id, popup_flags);
   8425     return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
   8426 }
   8427 
   8428 bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
   8429 {
   8430     ImGuiWindow* window = GImGui->CurrentWindow;
   8431     if (!str_id)
   8432         str_id = "void_context";
   8433     ImGuiID id = window->GetID(str_id);
   8434     int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
   8435     if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
   8436         if (GetTopMostPopupModal() == NULL)
   8437             OpenPopupEx(id, popup_flags);
   8438     return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
   8439 }
   8440 
   8441 // 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.)
   8442 // 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.
   8443 // (r_outer is usually equivalent to the viewport rectangle minus padding, but when multi-viewports are enabled and monitor
   8444 //  information are available, it may represent the entire platform monitor from the frame of reference of the current viewport.
   8445 //  this allows us to have tooltips/popups displayed out of the parent viewport.)
   8446 ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)
   8447 {
   8448     ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
   8449     //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
   8450     //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
   8451 
   8452     // Combo Box policy (we want a connecting edge)
   8453     if (policy == ImGuiPopupPositionPolicy_ComboBox)
   8454     {
   8455         const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };
   8456         for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
   8457         {
   8458             const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
   8459             if (n != -1 && dir == *last_dir) // Already tried this direction?
   8460                 continue;
   8461             ImVec2 pos;
   8462             if (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default)
   8463             if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
   8464             if (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
   8465             if (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
   8466             if (!r_outer.Contains(ImRect(pos, pos + size)))
   8467                 continue;
   8468             *last_dir = dir;
   8469             return pos;
   8470         }
   8471     }
   8472 
   8473     // Tooltip and Default popup policy
   8474     // (Always first try the direction we used on the last frame, if any)
   8475     if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default)
   8476     {
   8477         const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
   8478         for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
   8479         {
   8480             const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
   8481             if (n != -1 && dir == *last_dir) // Already tried this direction?
   8482                 continue;
   8483 
   8484             const 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);
   8485             const 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);
   8486 
   8487             // If there not enough room on one axis, there's no point in positioning on a side on this axis (e.g. when not enough width, use a top/bottom position to maximize available width)
   8488             if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right))
   8489                 continue;
   8490             if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down))
   8491                 continue;
   8492 
   8493             ImVec2 pos;
   8494             pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
   8495             pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
   8496 
   8497             // Clamp top-left corner of popup
   8498             pos.x = ImMax(pos.x, r_outer.Min.x);
   8499             pos.y = ImMax(pos.y, r_outer.Min.y);
   8500 
   8501             *last_dir = dir;
   8502             return pos;
   8503         }
   8504     }
   8505 
   8506     // Fallback when not enough room:
   8507     *last_dir = ImGuiDir_None;
   8508 
   8509     // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
   8510     if (policy == ImGuiPopupPositionPolicy_Tooltip)
   8511         return ref_pos + ImVec2(2, 2);
   8512 
   8513     // Otherwise try to keep within display
   8514     ImVec2 pos = ref_pos;
   8515     pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
   8516     pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
   8517     return pos;
   8518 }
   8519 
   8520 // Note that this is used for popups, which can overlap the non work-area of individual viewports.
   8521 ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
   8522 {
   8523     ImGuiContext& g = *GImGui;
   8524     IM_UNUSED(window);
   8525     ImRect r_screen = ((ImGuiViewportP*)(void*)GetMainViewport())->GetMainRect();
   8526     ImVec2 padding = g.Style.DisplaySafeAreaPadding;
   8527     r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
   8528     return r_screen;
   8529 }
   8530 
   8531 ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
   8532 {
   8533     ImGuiContext& g = *GImGui;
   8534 
   8535     ImRect r_outer = GetWindowAllowedExtentRect(window);
   8536     if (window->Flags & ImGuiWindowFlags_ChildMenu)
   8537     {
   8538         // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
   8539         // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
   8540         IM_ASSERT(g.CurrentWindow == window);
   8541         ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
   8542         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).
   8543         ImRect r_avoid;
   8544         if (parent_window->DC.MenuBarAppending)
   8545             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
   8546         else
   8547             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);
   8548         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
   8549     }
   8550     if (window->Flags & ImGuiWindowFlags_Popup)
   8551     {
   8552         ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
   8553         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
   8554     }
   8555     if (window->Flags & ImGuiWindowFlags_Tooltip)
   8556     {
   8557         // Position tooltip (always follows mouse)
   8558         float sc = g.Style.MouseCursorScale;
   8559         ImVec2 ref_pos = NavCalcPreferredRefPos();
   8560         ImRect r_avoid;
   8561         if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))
   8562             r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
   8563         else
   8564             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.
   8565         return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip);
   8566     }
   8567     IM_ASSERT(0);
   8568     return window->Pos;
   8569 }
   8570 
   8571 //-----------------------------------------------------------------------------
   8572 // [SECTION] KEYBOARD/GAMEPAD NAVIGATION
   8573 //-----------------------------------------------------------------------------
   8574 
   8575 // FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked.
   8576 void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
   8577 {
   8578     ImGuiContext& g = *GImGui;
   8579     IM_ASSERT(g.NavWindow != NULL);
   8580     IM_ASSERT(nav_layer == ImGuiNavLayer_Main || nav_layer == ImGuiNavLayer_Menu);
   8581     g.NavId = id;
   8582     g.NavLayer = nav_layer;
   8583     g.NavFocusScopeId = focus_scope_id;
   8584     g.NavWindow->NavLastIds[nav_layer] = id;
   8585     g.NavWindow->NavRectRel[nav_layer] = rect_rel;
   8586     //g.NavDisableHighlight = false;
   8587     //g.NavDisableMouseHover = g.NavMousePosDirty = true;
   8588 }
   8589 
   8590 void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
   8591 {
   8592     ImGuiContext& g = *GImGui;
   8593     IM_ASSERT(id != 0);
   8594 
   8595     // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid.
   8596     // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)
   8597     const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
   8598     if (g.NavWindow != window)
   8599         g.NavInitRequest = false;
   8600     g.NavWindow = window;
   8601     g.NavId = id;
   8602     g.NavLayer = nav_layer;
   8603     g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
   8604     window->NavLastIds[nav_layer] = id;
   8605     if (window->DC.LastItemId == id)
   8606         window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
   8607 
   8608     if (g.ActiveIdSource == ImGuiInputSource_Nav)
   8609         g.NavDisableMouseHover = true;
   8610     else
   8611         g.NavDisableHighlight = true;
   8612 }
   8613 
   8614 ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
   8615 {
   8616     if (ImFabs(dx) > ImFabs(dy))
   8617         return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
   8618     return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
   8619 }
   8620 
   8621 static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
   8622 {
   8623     if (a1 < b0)
   8624         return a1 - b0;
   8625     if (b1 < a0)
   8626         return a0 - b1;
   8627     return 0.0f;
   8628 }
   8629 
   8630 static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
   8631 {
   8632     if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
   8633     {
   8634         r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
   8635         r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
   8636     }
   8637     else
   8638     {
   8639         r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
   8640         r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
   8641     }
   8642 }
   8643 
   8644 // Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
   8645 static bool ImGui::NavScoreItem(ImGuiNavItemData* result, ImRect cand)
   8646 {
   8647     ImGuiContext& g = *GImGui;
   8648     ImGuiWindow* window = g.CurrentWindow;
   8649     if (g.NavLayer != window->DC.NavLayerCurrent)
   8650         return false;
   8651 
   8652     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)
   8653     g.NavScoringCount++;
   8654 
   8655     // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
   8656     if (window->ParentWindow == g.NavWindow)
   8657     {
   8658         IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
   8659         if (!window->ClipRect.Overlaps(cand))
   8660             return false;
   8661         cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
   8662     }
   8663 
   8664     // 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)
   8665     // For example, this ensure that items in one column are not reached when moving vertically from items in another column.
   8666     NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect);
   8667 
   8668     // Compute distance between boxes
   8669     // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
   8670     float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
   8671     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
   8672     if (dby != 0.0f && dbx != 0.0f)
   8673         dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
   8674     float dist_box = ImFabs(dbx) + ImFabs(dby);
   8675 
   8676     // 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)
   8677     float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
   8678     float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
   8679     float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
   8680 
   8681     // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
   8682     ImGuiDir quadrant;
   8683     float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
   8684     if (dbx != 0.0f || dby != 0.0f)
   8685     {
   8686         // For non-overlapping boxes, use distance between boxes
   8687         dax = dbx;
   8688         day = dby;
   8689         dist_axial = dist_box;
   8690         quadrant = ImGetDirQuadrantFromDelta(dbx, dby);
   8691     }
   8692     else if (dcx != 0.0f || dcy != 0.0f)
   8693     {
   8694         // For overlapping boxes with different centers, use distance between centers
   8695         dax = dcx;
   8696         day = dcy;
   8697         dist_axial = dist_center;
   8698         quadrant = ImGetDirQuadrantFromDelta(dcx, dcy);
   8699     }
   8700     else
   8701     {
   8702         // 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)
   8703         quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
   8704     }
   8705 
   8706 #if IMGUI_DEBUG_NAV_SCORING
   8707     char buf[128];
   8708     if (IsMouseHoveringRect(cand.Min, cand.Max))
   8709     {
   8710         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]);
   8711         ImDrawList* draw_list = GetForegroundDrawList(window);
   8712         draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
   8713         draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
   8714         draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150));
   8715         draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
   8716     }
   8717     else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
   8718     {
   8719         if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
   8720         if (quadrant == g.NavMoveDir)
   8721         {
   8722             ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
   8723             ImDrawList* draw_list = GetForegroundDrawList(window);
   8724             draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
   8725             draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
   8726         }
   8727     }
   8728 #endif
   8729 
   8730     // Is it in the quadrant we're interesting in moving to?
   8731     bool new_best = false;
   8732     if (quadrant == g.NavMoveDir)
   8733     {
   8734         // Does it beat the current best candidate?
   8735         if (dist_box < result->DistBox)
   8736         {
   8737             result->DistBox = dist_box;
   8738             result->DistCenter = dist_center;
   8739             return true;
   8740         }
   8741         if (dist_box == result->DistBox)
   8742         {
   8743             // Try using distance between center points to break ties
   8744             if (dist_center < result->DistCenter)
   8745             {
   8746                 result->DistCenter = dist_center;
   8747                 new_best = true;
   8748             }
   8749             else if (dist_center == result->DistCenter)
   8750             {
   8751                 // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
   8752                 // (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),
   8753                 // 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.
   8754                 if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
   8755                     new_best = true;
   8756             }
   8757         }
   8758     }
   8759 
   8760     // 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
   8761     // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
   8762     // 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.
   8763     // 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.
   8764     // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
   8765     if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)  // Check axial match
   8766         if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
   8767             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))
   8768             {
   8769                 result->DistAxial = dist_axial;
   8770                 new_best = true;
   8771             }
   8772 
   8773     return new_best;
   8774 }
   8775 
   8776 static void ImGui::NavApplyItemToResult(ImGuiNavItemData* result, ImGuiWindow* window, ImGuiID id, const ImRect& nav_bb_rel)
   8777 {
   8778     result->Window = window;
   8779     result->ID = id;
   8780     result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
   8781     result->RectRel = nav_bb_rel;
   8782 }
   8783 
   8784 // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
   8785 static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
   8786 {
   8787     ImGuiContext& g = *GImGui;
   8788     //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.
   8789     //    return;
   8790 
   8791     const ImGuiItemFlags item_flags = g.CurrentItemFlags;
   8792     const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
   8793 
   8794     // Process Init Request
   8795     if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
   8796     {
   8797         // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
   8798         if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
   8799         {
   8800             g.NavInitResultId = id;
   8801             g.NavInitResultRectRel = nav_bb_rel;
   8802         }
   8803         if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
   8804         {
   8805             g.NavInitRequest = false; // Found a match, clear request
   8806             NavUpdateAnyRequestFlag();
   8807         }
   8808     }
   8809 
   8810     // Process Move Request (scoring for navigation)
   8811     // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
   8812     if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
   8813     {
   8814         ImGuiNavItemData* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
   8815 #if IMGUI_DEBUG_NAV_SCORING
   8816         // [DEBUG] Score all items in NavWindow at all times
   8817         if (!g.NavMoveRequest)
   8818             g.NavMoveDir = g.NavMoveDirLast;
   8819         bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
   8820 #else
   8821         bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
   8822 #endif
   8823         if (new_best)
   8824             NavApplyItemToResult(result, window, id, nav_bb_rel);
   8825 
   8826         // Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
   8827         const float VISIBLE_RATIO = 0.70f;
   8828         if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
   8829             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)
   8830                 if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb))
   8831                     NavApplyItemToResult(&g.NavMoveResultLocalVisibleSet, window, id, nav_bb_rel);
   8832     }
   8833 
   8834     // Update window-relative bounding box of navigated item
   8835     if (g.NavId == id)
   8836     {
   8837         g.NavWindow = window;                                           // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
   8838         g.NavLayer = window->DC.NavLayerCurrent;
   8839         g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
   8840         g.NavIdIsAlive = true;
   8841         window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel;    // Store item bounding box (relative to window position)
   8842     }
   8843 }
   8844 
   8845 bool ImGui::NavMoveRequestButNoResultYet()
   8846 {
   8847     ImGuiContext& g = *GImGui;
   8848     return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
   8849 }
   8850 
   8851 void ImGui::NavMoveRequestCancel()
   8852 {
   8853     ImGuiContext& g = *GImGui;
   8854     g.NavMoveRequest = false;
   8855     NavUpdateAnyRequestFlag();
   8856 }
   8857 
   8858 void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags)
   8859 {
   8860     ImGuiContext& g = *GImGui;
   8861     IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
   8862     NavMoveRequestCancel();
   8863     g.NavMoveDir = move_dir;
   8864     g.NavMoveClipDir = clip_dir;
   8865     g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
   8866     g.NavMoveRequestFlags = move_flags;
   8867     g.NavWindow->NavRectRel[g.NavLayer] = bb_rel;
   8868 }
   8869 
   8870 void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags)
   8871 {
   8872     ImGuiContext& g = *GImGui;
   8873 
   8874     // Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
   8875     // popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.
   8876     g.NavWrapRequestWindow = window;
   8877     g.NavWrapRequestFlags = move_flags;
   8878 }
   8879 
   8880 // FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
   8881 // This way we could find the last focused window among our children. It would be much less confusing this way?
   8882 static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window)
   8883 {
   8884     ImGuiWindow* parent = nav_window;
   8885     while (parent && parent->RootWindow != parent && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
   8886         parent = parent->ParentWindow;
   8887     if (parent && parent != nav_window)
   8888         parent->NavLastChildNavWindow = nav_window;
   8889 }
   8890 
   8891 // Restore the last focused child.
   8892 // Call when we are expected to land on the Main Layer (0) after FocusWindow()
   8893 static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)
   8894 {
   8895     if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive)
   8896         return window->NavLastChildNavWindow;
   8897     return window;
   8898 }
   8899 
   8900 void ImGui::NavRestoreLayer(ImGuiNavLayer layer)
   8901 {
   8902     ImGuiContext& g = *GImGui;
   8903     if (layer == ImGuiNavLayer_Main)
   8904         g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow);
   8905     ImGuiWindow* window = g.NavWindow;
   8906     if (window->NavLastIds[layer] != 0)
   8907     {
   8908         SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);
   8909         g.NavDisableHighlight = false;
   8910         g.NavDisableMouseHover = g.NavMousePosDirty = true;
   8911     }
   8912     else
   8913     {
   8914         g.NavLayer = layer;
   8915         NavInitWindow(window, true);
   8916     }
   8917 }
   8918 
   8919 static inline void ImGui::NavUpdateAnyRequestFlag()
   8920 {
   8921     ImGuiContext& g = *GImGui;
   8922     g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
   8923     if (g.NavAnyRequest)
   8924         IM_ASSERT(g.NavWindow != NULL);
   8925 }
   8926 
   8927 // This needs to be called before we submit any widget (aka in or before Begin)
   8928 void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
   8929 {
   8930     ImGuiContext& g = *GImGui;
   8931     IM_ASSERT(window == g.NavWindow);
   8932 
   8933     if (window->Flags & ImGuiWindowFlags_NoNavInputs)
   8934     {
   8935         g.NavId = g.NavFocusScopeId = 0;
   8936         return;
   8937     }
   8938 
   8939     bool init_for_nav = false;
   8940     if (window == window->RootWindow || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
   8941         init_for_nav = true;
   8942     IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
   8943     if (init_for_nav)
   8944     {
   8945         SetNavID(0, g.NavLayer, 0, ImRect());
   8946         g.NavInitRequest = true;
   8947         g.NavInitRequestFromMove = false;
   8948         g.NavInitResultId = 0;
   8949         g.NavInitResultRectRel = ImRect();
   8950         NavUpdateAnyRequestFlag();
   8951     }
   8952     else
   8953     {
   8954         g.NavId = window->NavLastIds[0];
   8955         g.NavFocusScopeId = 0;
   8956     }
   8957 }
   8958 
   8959 static ImVec2 ImGui::NavCalcPreferredRefPos()
   8960 {
   8961     ImGuiContext& g = *GImGui;
   8962     if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow)
   8963     {
   8964         // Mouse (we need a fallback in case the mouse becomes invalid after being used)
   8965         if (IsMousePosValid(&g.IO.MousePos))
   8966             return g.IO.MousePos;
   8967         return g.LastValidMousePos;
   8968     }
   8969     else
   8970     {
   8971         // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item.
   8972         const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
   8973         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()));
   8974         ImGuiViewport* viewport = GetMainViewport();
   8975         return ImFloor(ImClamp(pos, viewport->Pos, viewport->Pos + viewport->Size)); // ImFloor() is important because non-integer mouse position application in backend might be lossy and result in undesirable non-zero delta.
   8976     }
   8977 }
   8978 
   8979 float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
   8980 {
   8981     ImGuiContext& g = *GImGui;
   8982     if (mode == ImGuiInputReadMode_Down)
   8983         return g.IO.NavInputs[n];                         // Instant, read analog input (0.0f..1.0f, as provided by user)
   8984 
   8985     const float t = g.IO.NavInputsDownDuration[n];
   8986     if (t < 0.0f && mode == ImGuiInputReadMode_Released)  // Return 1.0f when just released, no repeat, ignore analog input.
   8987         return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
   8988     if (t < 0.0f)
   8989         return 0.0f;
   8990     if (mode == ImGuiInputReadMode_Pressed)               // Return 1.0f when just pressed, no repeat, ignore analog input.
   8991         return (t == 0.0f) ? 1.0f : 0.0f;
   8992     if (mode == ImGuiInputReadMode_Repeat)
   8993         return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f);
   8994     if (mode == ImGuiInputReadMode_RepeatSlow)
   8995         return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f);
   8996     if (mode == ImGuiInputReadMode_RepeatFast)
   8997         return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f);
   8998     return 0.0f;
   8999 }
   9000 
   9001 ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
   9002 {
   9003     ImVec2 delta(0.0f, 0.0f);
   9004     if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
   9005         delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode)   - GetNavInputAmount(ImGuiNavInput_KeyLeft_,   mode), GetNavInputAmount(ImGuiNavInput_KeyDown_,   mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_,   mode));
   9006     if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
   9007         delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode)   - GetNavInputAmount(ImGuiNavInput_DpadLeft,   mode), GetNavInputAmount(ImGuiNavInput_DpadDown,   mode) - GetNavInputAmount(ImGuiNavInput_DpadUp,   mode));
   9008     if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
   9009         delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
   9010     if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
   9011         delta *= slow_factor;
   9012     if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
   9013         delta *= fast_factor;
   9014     return delta;
   9015 }
   9016 
   9017 static void ImGui::NavUpdate()
   9018 {
   9019     ImGuiContext& g = *GImGui;
   9020     ImGuiIO& io = g.IO;
   9021 
   9022     io.WantSetMousePos = false;
   9023     g.NavWrapRequestWindow = NULL;
   9024     g.NavWrapRequestFlags = ImGuiNavMoveFlags_None;
   9025 #if 0
   9026     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);
   9027 #endif
   9028 
   9029     // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
   9030     // (do it before we map Keyboard input!)
   9031     bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
   9032     bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
   9033     if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_Gamepad)
   9034     {
   9035         if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f
   9036             || io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f)
   9037             g.NavInputSource = ImGuiInputSource_Gamepad;
   9038     }
   9039 
   9040     // Update Keyboard->Nav inputs mapping
   9041     if (nav_keyboard_active)
   9042     {
   9043         #define NAV_MAP_KEY(_KEY, _NAV_INPUT)  do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_Keyboard; } } while (0)
   9044         NAV_MAP_KEY(ImGuiKey_Space,     ImGuiNavInput_Activate );
   9045         NAV_MAP_KEY(ImGuiKey_Enter,     ImGuiNavInput_Input    );
   9046         NAV_MAP_KEY(ImGuiKey_Escape,    ImGuiNavInput_Cancel   );
   9047         NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
   9048         NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
   9049         NAV_MAP_KEY(ImGuiKey_UpArrow,   ImGuiNavInput_KeyUp_   );
   9050         NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
   9051         if (io.KeyCtrl)
   9052             io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
   9053         if (io.KeyShift)
   9054             io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
   9055 
   9056         // AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl)
   9057         // But also even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.
   9058         if (io.KeyAlt && !io.KeyCtrl)
   9059             io.NavInputs[ImGuiNavInput_KeyMenu_]  = 1.0f;
   9060 
   9061         // We automatically cancel toggling nav layer when any text has been typed while holding Alt. (See #370)
   9062         if (io.KeyAlt && !io.KeyCtrl && g.NavWindowingToggleLayer && io.InputQueueCharacters.Size > 0)
   9063             g.NavWindowingToggleLayer = false;
   9064 
   9065         #undef NAV_MAP_KEY
   9066     }
   9067     memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration));
   9068     for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++)
   9069         io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f;
   9070 
   9071     // Process navigation init request (select first/default focus)
   9072     if (g.NavInitResultId != 0)
   9073         NavUpdateInitResult();
   9074     g.NavInitRequest = false;
   9075     g.NavInitRequestFromMove = false;
   9076     g.NavInitResultId = 0;
   9077     g.NavJustMovedToId = 0;
   9078 
   9079     // Process navigation move request
   9080     if (g.NavMoveRequest)
   9081         NavUpdateMoveResult();
   9082 
   9083     // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
   9084     if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
   9085     {
   9086         IM_ASSERT(g.NavMoveRequest);
   9087         if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
   9088             g.NavDisableHighlight = false;
   9089         g.NavMoveRequestForward = ImGuiNavForward_None;
   9090     }
   9091 
   9092     // Apply application mouse position movement, after we had a chance to process move request result.
   9093     if (g.NavMousePosDirty && g.NavIdIsAlive)
   9094     {
   9095         // Set mouse position given our knowledge of the navigated item position from last frame
   9096         if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
   9097             if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
   9098             {
   9099                 io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos();
   9100                 io.WantSetMousePos = true;
   9101             }
   9102         g.NavMousePosDirty = false;
   9103     }
   9104     g.NavIdIsAlive = false;
   9105     g.NavJustTabbedId = 0;
   9106     IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
   9107 
   9108     // 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
   9109     if (g.NavWindow)
   9110         NavSaveLastChildNavWindowIntoParent(g.NavWindow);
   9111     if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main)
   9112         g.NavWindow->NavLastChildNavWindow = NULL;
   9113 
   9114     // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
   9115     NavUpdateWindowing();
   9116 
   9117     // Set output flags for user application
   9118     io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
   9119     io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
   9120 
   9121     // Process NavCancel input (to close a popup, get back to parent, clear focus)
   9122     if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
   9123     {
   9124         IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
   9125         if (g.ActiveId != 0)
   9126         {
   9127             if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
   9128                 ClearActiveID();
   9129         }
   9130         else if (g.NavLayer != ImGuiNavLayer_Main)
   9131         {
   9132             // Leave the "menu" layer
   9133             NavRestoreLayer(ImGuiNavLayer_Main);
   9134         }
   9135         else if (g.NavWindow && g.NavWindow != g.NavWindow->RootWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
   9136         {
   9137             // Exit child window
   9138             ImGuiWindow* child_window = g.NavWindow;
   9139             ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
   9140             IM_ASSERT(child_window->ChildId != 0);
   9141             ImRect child_rect = child_window->Rect();
   9142             FocusWindow(parent_window);
   9143             SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, ImRect(child_rect.Min - parent_window->Pos, child_rect.Max - parent_window->Pos));
   9144         }
   9145         else if (g.OpenPopupStack.Size > 0)
   9146         {
   9147             // Close open popup/menu
   9148             if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
   9149                 ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
   9150         }
   9151         else
   9152         {
   9153             // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
   9154             if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
   9155                 g.NavWindow->NavLastIds[0] = 0;
   9156             g.NavId = g.NavFocusScopeId = 0;
   9157         }
   9158     }
   9159 
   9160     // Process manual activation request
   9161     g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
   9162     if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
   9163     {
   9164         bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
   9165         bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
   9166         if (g.ActiveId == 0 && activate_pressed)
   9167             g.NavActivateId = g.NavId;
   9168         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
   9169             g.NavActivateDownId = g.NavId;
   9170         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
   9171             g.NavActivatePressedId = g.NavId;
   9172         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
   9173             g.NavInputId = g.NavId;
   9174     }
   9175     if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
   9176         g.NavDisableHighlight = true;
   9177     if (g.NavActivateId != 0)
   9178         IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
   9179     g.NavMoveRequest = false;
   9180 
   9181     // Process programmatic activation request
   9182     if (g.NavNextActivateId != 0)
   9183         g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
   9184     g.NavNextActivateId = 0;
   9185 
   9186     // Initiate directional inputs request
   9187     if (g.NavMoveRequestForward == ImGuiNavForward_None)
   9188     {
   9189         g.NavMoveDir = ImGuiDir_None;
   9190         g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
   9191         if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
   9192         {
   9193             const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
   9194             if (!IsActiveIdUsingNavDir(ImGuiDir_Left)  && (IsNavInputTest(ImGuiNavInput_DpadLeft,  read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_,  read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
   9195             if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
   9196             if (!IsActiveIdUsingNavDir(ImGuiDir_Up)    && (IsNavInputTest(ImGuiNavInput_DpadUp,    read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_,    read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
   9197             if (!IsActiveIdUsingNavDir(ImGuiDir_Down)  && (IsNavInputTest(ImGuiNavInput_DpadDown,  read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_,  read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
   9198         }
   9199         g.NavMoveClipDir = g.NavMoveDir;
   9200     }
   9201     else
   9202     {
   9203         // 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)
   9204         // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
   9205         IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
   9206         IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
   9207         IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
   9208         g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
   9209     }
   9210 
   9211     // Update PageUp/PageDown/Home/End scroll
   9212     // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
   9213     float nav_scoring_rect_offset_y = 0.0f;
   9214     if (nav_keyboard_active)
   9215         nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
   9216 
   9217     // 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
   9218     if (g.NavMoveDir != ImGuiDir_None)
   9219     {
   9220         g.NavMoveRequest = true;
   9221         g.NavMoveRequestKeyMods = io.KeyMods;
   9222         g.NavMoveDirLast = g.NavMoveDir;
   9223     }
   9224     if (g.NavMoveRequest && g.NavId == 0)
   9225     {
   9226         IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
   9227         g.NavInitRequest = g.NavInitRequestFromMove = true;
   9228         // Reassigning with same value, we're being explicit here.
   9229         g.NavInitResultId = 0;     // -V1048
   9230         g.NavDisableHighlight = false;
   9231     }
   9232     NavUpdateAnyRequestFlag();
   9233 
   9234     // Scrolling
   9235     if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
   9236     {
   9237         // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
   9238         ImGuiWindow* window = g.NavWindow;
   9239         const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
   9240         if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
   9241         {
   9242             if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
   9243                 SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
   9244             if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
   9245                 SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
   9246         }
   9247 
   9248         // *Normal* Manual scroll with NavScrollXXX keys
   9249         // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
   9250         ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f);
   9251         if (scroll_dir.x != 0.0f && window->ScrollbarX)
   9252             SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
   9253         if (scroll_dir.y != 0.0f)
   9254             SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
   9255     }
   9256 
   9257     // Reset search results
   9258     g.NavMoveResultLocal.Clear();
   9259     g.NavMoveResultLocalVisibleSet.Clear();
   9260     g.NavMoveResultOther.Clear();
   9261 
   9262     // When using gamepad, we project the reference nav bounding box into window visible area.
   9263     // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
   9264     // (can't focus a visible object like we can with the mouse).
   9265     if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main)
   9266     {
   9267         ImGuiWindow* window = g.NavWindow;
   9268         ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
   9269         if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
   9270         {
   9271             IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
   9272             float pad = window->CalcFontSize() * 0.5f;
   9273             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
   9274             window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
   9275             g.NavId = g.NavFocusScopeId = 0;
   9276         }
   9277     }
   9278 
   9279     // 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)
   9280     ImRect nav_rect_rel = g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted() ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
   9281     g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : ImRect(0, 0, 0, 0);
   9282     g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
   9283     g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
   9284     g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
   9285     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().
   9286     //GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
   9287     g.NavScoringCount = 0;
   9288 #if IMGUI_DEBUG_NAV_RECTS
   9289     if (g.NavWindow)
   9290     {
   9291         ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow);
   9292         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]
   9293         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); }
   9294     }
   9295 #endif
   9296 }
   9297 
   9298 static void ImGui::NavUpdateInitResult()
   9299 {
   9300     // 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)
   9301     ImGuiContext& g = *GImGui;
   9302     if (!g.NavWindow)
   9303         return;
   9304 
   9305     // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
   9306     // FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
   9307     IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
   9308     SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
   9309     if (g.NavInitRequestFromMove)
   9310     {
   9311         g.NavDisableHighlight = false;
   9312         g.NavDisableMouseHover = g.NavMousePosDirty = true;
   9313     }
   9314 }
   9315 
   9316 // Apply result from previous frame navigation directional move request
   9317 static void ImGui::NavUpdateMoveResult()
   9318 {
   9319     ImGuiContext& g = *GImGui;
   9320     if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
   9321     {
   9322         // 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)
   9323         if (g.NavId != 0)
   9324         {
   9325             g.NavDisableHighlight = false;
   9326             g.NavDisableMouseHover = true;
   9327         }
   9328         return;
   9329     }
   9330 
   9331     // Select which result to use
   9332     ImGuiNavItemData* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
   9333 
   9334     // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
   9335     if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
   9336         if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId)
   9337             result = &g.NavMoveResultLocalVisibleSet;
   9338 
   9339     // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
   9340     if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)
   9341         if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter))
   9342             result = &g.NavMoveResultOther;
   9343     IM_ASSERT(g.NavWindow && result->Window);
   9344 
   9345     // Scroll to keep newly navigated item fully into view.
   9346     if (g.NavLayer == ImGuiNavLayer_Main)
   9347     {
   9348         ImVec2 delta_scroll;
   9349         if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge)
   9350         {
   9351             float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
   9352             delta_scroll.y = result->Window->Scroll.y - scroll_target;
   9353             SetScrollY(result->Window, scroll_target);
   9354         }
   9355         else
   9356         {
   9357             ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
   9358             delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
   9359         }
   9360 
   9361         // Offset our result position so mouse position can be applied immediately after in NavUpdate()
   9362         result->RectRel.TranslateX(-delta_scroll.x);
   9363         result->RectRel.TranslateY(-delta_scroll.y);
   9364     }
   9365 
   9366     ClearActiveID();
   9367     g.NavWindow = result->Window;
   9368     if (g.NavId != result->ID)
   9369     {
   9370         // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
   9371         g.NavJustMovedToId = result->ID;
   9372         g.NavJustMovedToFocusScopeId = result->FocusScopeId;
   9373         g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods;
   9374     }
   9375     IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
   9376     SetNavID(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
   9377     g.NavDisableHighlight = false;
   9378     g.NavDisableMouseHover = g.NavMousePosDirty = true;
   9379 }
   9380 
   9381 // Handle PageUp/PageDown/Home/End keys
   9382 static float ImGui::NavUpdatePageUpPageDown()
   9383 {
   9384     ImGuiContext& g = *GImGui;
   9385     ImGuiIO& io = g.IO;
   9386 
   9387     if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL)
   9388         return 0.0f;
   9389     if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main)
   9390         return 0.0f;
   9391 
   9392     ImGuiWindow* window = g.NavWindow;
   9393     const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
   9394     const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
   9395     const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
   9396     const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
   9397     if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
   9398     {
   9399         if (window->DC.NavLayersActiveMask == 0x00 && window->DC.NavHasScroll)
   9400         {
   9401             // Fallback manual-scroll when window has no navigable item
   9402             if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
   9403                 SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
   9404             else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
   9405                 SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
   9406             else if (home_pressed)
   9407                 SetScrollY(window, 0.0f);
   9408             else if (end_pressed)
   9409                 SetScrollY(window, window->ScrollMax.y);
   9410         }
   9411         else
   9412         {
   9413             ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
   9414             const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
   9415             float nav_scoring_rect_offset_y = 0.0f;
   9416             if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
   9417             {
   9418                 nav_scoring_rect_offset_y = -page_offset_y;
   9419                 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)
   9420                 g.NavMoveClipDir = ImGuiDir_Up;
   9421                 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
   9422             }
   9423             else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
   9424             {
   9425                 nav_scoring_rect_offset_y = +page_offset_y;
   9426                 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)
   9427                 g.NavMoveClipDir = ImGuiDir_Down;
   9428                 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
   9429             }
   9430             else if (home_pressed)
   9431             {
   9432                 // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
   9433                 // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
   9434                 // Preserve current horizontal position if we have any.
   9435                 nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
   9436                 if (nav_rect_rel.IsInverted())
   9437                     nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
   9438                 g.NavMoveDir = ImGuiDir_Down;
   9439                 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
   9440             }
   9441             else if (end_pressed)
   9442             {
   9443                 nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
   9444                 if (nav_rect_rel.IsInverted())
   9445                     nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
   9446                 g.NavMoveDir = ImGuiDir_Up;
   9447                 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
   9448             }
   9449             return nav_scoring_rect_offset_y;
   9450         }
   9451     }
   9452     return 0.0f;
   9453 }
   9454 
   9455 static void ImGui::NavEndFrame()
   9456 {
   9457     ImGuiContext& g = *GImGui;
   9458 
   9459     // Show CTRL+TAB list window
   9460     if (g.NavWindowingTarget != NULL)
   9461         NavUpdateWindowingOverlay();
   9462 
   9463     // Perform wrap-around in menus
   9464     ImGuiWindow* window = g.NavWrapRequestWindow;
   9465     ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags;
   9466     if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main)
   9467     {
   9468         IM_ASSERT(move_flags != 0); // No points calling this with no wrapping
   9469         ImRect bb_rel = window->NavRectRel[0];
   9470 
   9471         ImGuiDir clip_dir = g.NavMoveDir;
   9472         if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
   9473         {
   9474             bb_rel.Min.x = bb_rel.Max.x =
   9475                 ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x;
   9476             if (move_flags & ImGuiNavMoveFlags_WrapX)
   9477             {
   9478                 bb_rel.TranslateY(-bb_rel.GetHeight());
   9479                 clip_dir = ImGuiDir_Up;
   9480             }
   9481             NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
   9482         }
   9483         if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
   9484         {
   9485             bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x;
   9486             if (move_flags & ImGuiNavMoveFlags_WrapX)
   9487             {
   9488                 bb_rel.TranslateY(+bb_rel.GetHeight());
   9489                 clip_dir = ImGuiDir_Down;
   9490             }
   9491             NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
   9492         }
   9493         if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
   9494         {
   9495             bb_rel.Min.y = bb_rel.Max.y =
   9496                 ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y;
   9497             if (move_flags & ImGuiNavMoveFlags_WrapY)
   9498             {
   9499                 bb_rel.TranslateX(-bb_rel.GetWidth());
   9500                 clip_dir = ImGuiDir_Left;
   9501             }
   9502             NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
   9503         }
   9504         if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
   9505         {
   9506             bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y;
   9507             if (move_flags & ImGuiNavMoveFlags_WrapY)
   9508             {
   9509                 bb_rel.TranslateX(+bb_rel.GetWidth());
   9510                 clip_dir = ImGuiDir_Right;
   9511             }
   9512             NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
   9513         }
   9514     }
   9515 }
   9516 
   9517 static int ImGui::FindWindowFocusIndex(ImGuiWindow* window)
   9518 {
   9519     ImGuiContext& g = *GImGui;
   9520     IM_UNUSED(g);
   9521     int order = window->FocusOrder;
   9522     IM_ASSERT(g.WindowsFocusOrder[order] == window);
   9523     return order;
   9524 }
   9525 
   9526 static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
   9527 {
   9528     ImGuiContext& g = *GImGui;
   9529     for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)
   9530         if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i]))
   9531             return g.WindowsFocusOrder[i];
   9532     return NULL;
   9533 }
   9534 
   9535 static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
   9536 {
   9537     ImGuiContext& g = *GImGui;
   9538     IM_ASSERT(g.NavWindowingTarget);
   9539     if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
   9540         return;
   9541 
   9542     const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget);
   9543     ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
   9544     if (!window_target)
   9545         window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);
   9546     if (window_target) // Don't reset windowing target if there's a single window in the list
   9547         g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
   9548     g.NavWindowingToggleLayer = false;
   9549 }
   9550 
   9551 // Windowing management mode
   9552 // Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer)
   9553 // Gamepad:  Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer)
   9554 static void ImGui::NavUpdateWindowing()
   9555 {
   9556     ImGuiContext& g = *GImGui;
   9557     ImGuiWindow* apply_focus_window = NULL;
   9558     bool apply_toggle_layer = false;
   9559 
   9560     ImGuiWindow* modal_window = GetTopMostPopupModal();
   9561     bool allow_windowing = (modal_window == NULL);
   9562     if (!allow_windowing)
   9563         g.NavWindowingTarget = NULL;
   9564 
   9565     // Fade out
   9566     if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
   9567     {
   9568         g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f);
   9569         if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
   9570             g.NavWindowingTargetAnim = NULL;
   9571     }
   9572 
   9573     // Start CTRL-TAB or Square+L/R window selection
   9574     bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
   9575     bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
   9576     if (start_windowing_with_gamepad || start_windowing_with_keyboard)
   9577         if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
   9578         {
   9579             g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // FIXME-DOCK: Will need to use RootWindowDockStop
   9580             g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
   9581             g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
   9582             g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_Keyboard : ImGuiInputSource_Gamepad;
   9583         }
   9584 
   9585     // Gamepad update
   9586     g.NavWindowingTimer += g.IO.DeltaTime;
   9587     if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Gamepad)
   9588     {
   9589         // 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
   9590         g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
   9591 
   9592         // Select window to focus
   9593         const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
   9594         if (focus_change_dir != 0)
   9595         {
   9596             NavUpdateWindowingHighlightWindow(focus_change_dir);
   9597             g.NavWindowingHighlightAlpha = 1.0f;
   9598         }
   9599 
   9600         // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)
   9601         if (!IsNavInputDown(ImGuiNavInput_Menu))
   9602         {
   9603             g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
   9604             if (g.NavWindowingToggleLayer && g.NavWindow)
   9605                 apply_toggle_layer = true;
   9606             else if (!g.NavWindowingToggleLayer)
   9607                 apply_focus_window = g.NavWindowingTarget;
   9608             g.NavWindowingTarget = NULL;
   9609         }
   9610     }
   9611 
   9612     // Keyboard: Focus
   9613     if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_Keyboard)
   9614     {
   9615         // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
   9616         g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
   9617         if (IsKeyPressedMap(ImGuiKey_Tab, true))
   9618             NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
   9619         if (!g.IO.KeyCtrl)
   9620             apply_focus_window = g.NavWindowingTarget;
   9621     }
   9622 
   9623     // Keyboard: Press and Release ALT to toggle menu layer
   9624     // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of backend clearing releases all keys on ALT-TAB
   9625     if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed))
   9626         g.NavWindowingToggleLayer = true;
   9627     if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
   9628         if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
   9629             apply_toggle_layer = true;
   9630 
   9631     // Move window
   9632     if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
   9633     {
   9634         ImVec2 move_delta;
   9635         if (g.NavInputSource == ImGuiInputSource_Keyboard && !g.IO.KeyShift)
   9636             move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
   9637         if (g.NavInputSource == ImGuiInputSource_Gamepad)
   9638             move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
   9639         if (move_delta.x != 0.0f || move_delta.y != 0.0f)
   9640         {
   9641             const float NAV_MOVE_SPEED = 800.0f;
   9642             const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't handle variable framerate very well
   9643             ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow;
   9644             SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always);
   9645             MarkIniSettingsDirty(moving_window);
   9646             g.NavDisableMouseHover = true;
   9647         }
   9648     }
   9649 
   9650     // Apply final focus
   9651     if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
   9652     {
   9653         ClearActiveID();
   9654         g.NavDisableHighlight = false;
   9655         g.NavDisableMouseHover = true;
   9656         apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
   9657         ClosePopupsOverWindow(apply_focus_window, false);
   9658         FocusWindow(apply_focus_window);
   9659         if (apply_focus_window->NavLastIds[0] == 0)
   9660             NavInitWindow(apply_focus_window, false);
   9661 
   9662         // If the window has ONLY a menu layer (no main layer), select it directly
   9663         // Use NavLayersActiveMaskNext since windows didn't have a chance to be Begin()-ed on this frame,
   9664         // so CTRL+Tab where the keys are only held for 1 frame will be able to use correct layers mask since
   9665         // the target window as already been previewed once.
   9666         // FIXME-NAV: This should be done in NavInit.. or in FocusWindow... However in both of those cases,
   9667         // we won't have a guarantee that windows has been visible before and therefore NavLayersActiveMask*
   9668         // won't be valid.
   9669         if (apply_focus_window->DC.NavLayersActiveMaskNext == (1 << ImGuiNavLayer_Menu))
   9670             g.NavLayer = ImGuiNavLayer_Menu;
   9671     }
   9672     if (apply_focus_window)
   9673         g.NavWindowingTarget = NULL;
   9674 
   9675     // Apply menu/layer toggle
   9676     if (apply_toggle_layer && g.NavWindow)
   9677     {
   9678         ClearActiveID();
   9679 
   9680         // Move to parent menu if necessary
   9681         ImGuiWindow* new_nav_window = g.NavWindow;
   9682         while (new_nav_window->ParentWindow
   9683             && (new_nav_window->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
   9684             && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
   9685             && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
   9686             new_nav_window = new_nav_window->ParentWindow;
   9687         if (new_nav_window != g.NavWindow)
   9688         {
   9689             ImGuiWindow* old_nav_window = g.NavWindow;
   9690             FocusWindow(new_nav_window);
   9691             new_nav_window->NavLastChildNavWindow = old_nav_window;
   9692         }
   9693         g.NavDisableHighlight = false;
   9694         g.NavDisableMouseHover = true;
   9695 
   9696         // Reinitialize navigation when entering menu bar with the Alt key.
   9697         const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayersActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
   9698         if (new_nav_layer == ImGuiNavLayer_Menu)
   9699             g.NavWindow->NavLastIds[new_nav_layer] = 0;
   9700         NavRestoreLayer(new_nav_layer);
   9701     }
   9702 }
   9703 
   9704 // Window has already passed the IsWindowNavFocusable()
   9705 static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
   9706 {
   9707     if (window->Flags & ImGuiWindowFlags_Popup)
   9708         return "(Popup)";
   9709     if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
   9710         return "(Main menu bar)";
   9711     return "(Untitled)";
   9712 }
   9713 
   9714 // Overlay displayed when using CTRL+TAB. Called by EndFrame().
   9715 void ImGui::NavUpdateWindowingOverlay()
   9716 {
   9717     ImGuiContext& g = *GImGui;
   9718     IM_ASSERT(g.NavWindowingTarget != NULL);
   9719 
   9720     if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)
   9721         return;
   9722 
   9723     if (g.NavWindowingListWindow == NULL)
   9724         g.NavWindowingListWindow = FindWindowByName("###NavWindowingList");
   9725     const ImGuiViewport* viewport = GetMainViewport();
   9726     SetNextWindowSizeConstraints(ImVec2(viewport->Size.x * 0.20f, viewport->Size.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
   9727     SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
   9728     PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
   9729     Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
   9730     for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
   9731     {
   9732         ImGuiWindow* window = g.WindowsFocusOrder[n];
   9733         IM_ASSERT(window != NULL); // Fix static analyzers
   9734         if (!IsWindowNavFocusable(window))
   9735             continue;
   9736         const char* label = window->Name;
   9737         if (label == FindRenderedTextEnd(label))
   9738             label = GetFallbackWindowNameForWindowingList(window);
   9739         Selectable(label, g.NavWindowingTarget == window);
   9740     }
   9741     End();
   9742     PopStyleVar();
   9743 }
   9744 
   9745 
   9746 //-----------------------------------------------------------------------------
   9747 // [SECTION] DRAG AND DROP
   9748 //-----------------------------------------------------------------------------
   9749 
   9750 void ImGui::ClearDragDrop()
   9751 {
   9752     ImGuiContext& g = *GImGui;
   9753     g.DragDropActive = false;
   9754     g.DragDropPayload.Clear();
   9755     g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
   9756     g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
   9757     g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
   9758     g.DragDropAcceptFrameCount = -1;
   9759 
   9760     g.DragDropPayloadBufHeap.clear();
   9761     memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
   9762 }
   9763 
   9764 // When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
   9765 // If the item has an identifier:
   9766 // - This assume/require the item to be activated (typically via ButtonBehavior).
   9767 // - Therefore if you want to use this with a mouse button other than left mouse button, it is up to the item itself to activate with another button.
   9768 // - We then pull and use the mouse button that was used to activate the item and use it to carry on the drag.
   9769 // If the item has no identifier:
   9770 // - Currently always assume left mouse button.
   9771 bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
   9772 {
   9773     ImGuiContext& g = *GImGui;
   9774     ImGuiWindow* window = g.CurrentWindow;
   9775 
   9776     // FIXME-DRAGDROP: While in the common-most "drag from non-zero active id" case we can tell the mouse button,
   9777     // in both SourceExtern and id==0 cases we may requires something else (explicit flags or some heuristic).
   9778     ImGuiMouseButton mouse_button = ImGuiMouseButton_Left;
   9779 
   9780     bool source_drag_active = false;
   9781     ImGuiID source_id = 0;
   9782     ImGuiID source_parent_id = 0;
   9783     if (!(flags & ImGuiDragDropFlags_SourceExtern))
   9784     {
   9785         source_id = window->DC.LastItemId;
   9786         if (source_id != 0)
   9787         {
   9788             // Common path: items with ID
   9789             if (g.ActiveId != source_id)
   9790                 return false;
   9791             if (g.ActiveIdMouseButton != -1)
   9792                 mouse_button = g.ActiveIdMouseButton;
   9793             if (g.IO.MouseDown[mouse_button] == false)
   9794                 return false;
   9795             g.ActiveIdAllowOverlap = false;
   9796         }
   9797         else
   9798         {
   9799             // Uncommon path: items without ID
   9800             if (g.IO.MouseDown[mouse_button] == false)
   9801                 return false;
   9802 
   9803             // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
   9804             // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
   9805             if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
   9806             {
   9807                 IM_ASSERT(0);
   9808                 return false;
   9809             }
   9810 
   9811             // Early out
   9812             if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
   9813                 return false;
   9814 
   9815             // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
   9816             // We build a throwaway ID based on current ID stack + relative AABB of items in window.
   9817             // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
   9818             // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
   9819             source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
   9820             bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id);
   9821             if (is_hovered && g.IO.MouseClicked[mouse_button])
   9822             {
   9823                 SetActiveID(source_id, window);
   9824                 FocusWindow(window);
   9825             }
   9826             if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
   9827                 g.ActiveIdAllowOverlap = is_hovered;
   9828         }
   9829         if (g.ActiveId != source_id)
   9830             return false;
   9831         source_parent_id = window->IDStack.back();
   9832         source_drag_active = IsMouseDragging(mouse_button);
   9833 
   9834         // Disable navigation and key inputs while dragging
   9835         g.ActiveIdUsingNavDirMask = ~(ImU32)0;
   9836         g.ActiveIdUsingNavInputMask = ~(ImU32)0;
   9837         g.ActiveIdUsingKeyInputMask = ~(ImU64)0;
   9838     }
   9839     else
   9840     {
   9841         window = NULL;
   9842         source_id = ImHashStr("#SourceExtern");
   9843         source_drag_active = true;
   9844     }
   9845 
   9846     if (source_drag_active)
   9847     {
   9848         if (!g.DragDropActive)
   9849         {
   9850             IM_ASSERT(source_id != 0);
   9851             ClearDragDrop();
   9852             ImGuiPayload& payload = g.DragDropPayload;
   9853             payload.SourceId = source_id;
   9854             payload.SourceParentId = source_parent_id;
   9855             g.DragDropActive = true;
   9856             g.DragDropSourceFlags = flags;
   9857             g.DragDropMouseButton = mouse_button;
   9858             if (payload.SourceId == g.ActiveId)
   9859                 g.ActiveIdNoClearOnFocusLoss = true;
   9860         }
   9861         g.DragDropSourceFrameCount = g.FrameCount;
   9862         g.DragDropWithinSource = true;
   9863 
   9864         if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
   9865         {
   9866             // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
   9867             // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
   9868             BeginTooltip();
   9869             if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
   9870             {
   9871                 ImGuiWindow* tooltip_window = g.CurrentWindow;
   9872                 tooltip_window->SkipItems = true;
   9873                 tooltip_window->HiddenFramesCanSkipItems = 1;
   9874             }
   9875         }
   9876 
   9877         if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
   9878             window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
   9879 
   9880         return true;
   9881     }
   9882     return false;
   9883 }
   9884 
   9885 void ImGui::EndDragDropSource()
   9886 {
   9887     ImGuiContext& g = *GImGui;
   9888     IM_ASSERT(g.DragDropActive);
   9889     IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?");
   9890 
   9891     if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
   9892         EndTooltip();
   9893 
   9894     // Discard the drag if have not called SetDragDropPayload()
   9895     if (g.DragDropPayload.DataFrameCount == -1)
   9896         ClearDragDrop();
   9897     g.DragDropWithinSource = false;
   9898 }
   9899 
   9900 // Use 'cond' to choose to submit payload on drag start or every frame
   9901 bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
   9902 {
   9903     ImGuiContext& g = *GImGui;
   9904     ImGuiPayload& payload = g.DragDropPayload;
   9905     if (cond == 0)
   9906         cond = ImGuiCond_Always;
   9907 
   9908     IM_ASSERT(type != NULL);
   9909     IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
   9910     IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
   9911     IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
   9912     IM_ASSERT(payload.SourceId != 0);                               // Not called between BeginDragDropSource() and EndDragDropSource()
   9913 
   9914     if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
   9915     {
   9916         // Copy payload
   9917         ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
   9918         g.DragDropPayloadBufHeap.resize(0);
   9919         if (data_size > sizeof(g.DragDropPayloadBufLocal))
   9920         {
   9921             // Store in heap
   9922             g.DragDropPayloadBufHeap.resize((int)data_size);
   9923             payload.Data = g.DragDropPayloadBufHeap.Data;
   9924             memcpy(payload.Data, data, data_size);
   9925         }
   9926         else if (data_size > 0)
   9927         {
   9928             // Store locally
   9929             memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
   9930             payload.Data = g.DragDropPayloadBufLocal;
   9931             memcpy(payload.Data, data, data_size);
   9932         }
   9933         else
   9934         {
   9935             payload.Data = NULL;
   9936         }
   9937         payload.DataSize = (int)data_size;
   9938     }
   9939     payload.DataFrameCount = g.FrameCount;
   9940 
   9941     return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
   9942 }
   9943 
   9944 bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
   9945 {
   9946     ImGuiContext& g = *GImGui;
   9947     if (!g.DragDropActive)
   9948         return false;
   9949 
   9950     ImGuiWindow* window = g.CurrentWindow;
   9951     ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
   9952     if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
   9953         return false;
   9954     IM_ASSERT(id != 0);
   9955     if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
   9956         return false;
   9957     if (window->SkipItems)
   9958         return false;
   9959 
   9960     IM_ASSERT(g.DragDropWithinTarget == false);
   9961     g.DragDropTargetRect = bb;
   9962     g.DragDropTargetId = id;
   9963     g.DragDropWithinTarget = true;
   9964     return true;
   9965 }
   9966 
   9967 // We don't use BeginDragDropTargetCustom() and duplicate its code because:
   9968 // 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.
   9969 // 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
   9970 // Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
   9971 bool ImGui::BeginDragDropTarget()
   9972 {
   9973     ImGuiContext& g = *GImGui;
   9974     if (!g.DragDropActive)
   9975         return false;
   9976 
   9977     ImGuiWindow* window = g.CurrentWindow;
   9978     if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
   9979         return false;
   9980     ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
   9981     if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
   9982         return false;
   9983 
   9984     const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
   9985     ImGuiID id = window->DC.LastItemId;
   9986     if (id == 0)
   9987         id = window->GetIDFromRectangle(display_rect);
   9988     if (g.DragDropPayload.SourceId == id)
   9989         return false;
   9990 
   9991     IM_ASSERT(g.DragDropWithinTarget == false);
   9992     g.DragDropTargetRect = display_rect;
   9993     g.DragDropTargetId = id;
   9994     g.DragDropWithinTarget = true;
   9995     return true;
   9996 }
   9997 
   9998 bool ImGui::IsDragDropPayloadBeingAccepted()
   9999 {
  10000     ImGuiContext& g = *GImGui;
  10001     return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
  10002 }
  10003 
  10004 const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags)
  10005 {
  10006     ImGuiContext& g = *GImGui;
  10007     ImGuiWindow* window = g.CurrentWindow;
  10008     ImGuiPayload& payload = g.DragDropPayload;
  10009     IM_ASSERT(g.DragDropActive);                        // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
  10010     IM_ASSERT(payload.DataFrameCount != -1);            // Forgot to call EndDragDropTarget() ?
  10011     if (type != NULL && !payload.IsDataType(type))
  10012         return NULL;
  10013 
  10014     // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
  10015     // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
  10016     const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
  10017     ImRect r = g.DragDropTargetRect;
  10018     float r_surface = r.GetWidth() * r.GetHeight();
  10019     if (r_surface <= g.DragDropAcceptIdCurrRectSurface)
  10020     {
  10021         g.DragDropAcceptFlags = flags;
  10022         g.DragDropAcceptIdCurr = g.DragDropTargetId;
  10023         g.DragDropAcceptIdCurrRectSurface = r_surface;
  10024     }
  10025 
  10026     // Render default drop visuals
  10027     payload.Preview = was_accepted_previously;
  10028     flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
  10029     if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
  10030     {
  10031         // FIXME-DRAGDROP: Settle on a proper default visuals for drop target.
  10032         r.Expand(3.5f);
  10033         bool push_clip_rect = !window->ClipRect.Contains(r);
  10034         if (push_clip_rect) window->DrawList->PushClipRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1));
  10035         window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, 0, 2.0f);
  10036         if (push_clip_rect) window->DrawList->PopClipRect();
  10037     }
  10038 
  10039     g.DragDropAcceptFrameCount = g.FrameCount;
  10040     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()
  10041     if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
  10042         return NULL;
  10043 
  10044     return &payload;
  10045 }
  10046 
  10047 const ImGuiPayload* ImGui::GetDragDropPayload()
  10048 {
  10049     ImGuiContext& g = *GImGui;
  10050     return g.DragDropActive ? &g.DragDropPayload : NULL;
  10051 }
  10052 
  10053 // We don't really use/need this now, but added it for the sake of consistency and because we might need it later.
  10054 void ImGui::EndDragDropTarget()
  10055 {
  10056     ImGuiContext& g = *GImGui;
  10057     IM_ASSERT(g.DragDropActive);
  10058     IM_ASSERT(g.DragDropWithinTarget);
  10059     g.DragDropWithinTarget = false;
  10060 }
  10061 
  10062 //-----------------------------------------------------------------------------
  10063 // [SECTION] LOGGING/CAPTURING
  10064 //-----------------------------------------------------------------------------
  10065 // All text output from the interface can be captured into tty/file/clipboard.
  10066 // By default, tree nodes are automatically opened during logging.
  10067 //-----------------------------------------------------------------------------
  10068 
  10069 // Pass text data straight to log (without being displayed)
  10070 static inline void LogTextV(ImGuiContext& g, const char* fmt, va_list args)
  10071 {
  10072     if (g.LogFile)
  10073     {
  10074         g.LogBuffer.Buf.resize(0);
  10075         g.LogBuffer.appendfv(fmt, args);
  10076         ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);
  10077     }
  10078     else
  10079     {
  10080         g.LogBuffer.appendfv(fmt, args);
  10081     }
  10082 }
  10083 
  10084 void ImGui::LogText(const char* fmt, ...)
  10085 {
  10086     ImGuiContext& g = *GImGui;
  10087     if (!g.LogEnabled)
  10088         return;
  10089 
  10090     va_list args;
  10091     va_start(args, fmt);
  10092     LogTextV(g, fmt, args);
  10093     va_end(args);
  10094 }
  10095 
  10096 void ImGui::LogTextV(const char* fmt, va_list args)
  10097 {
  10098     ImGuiContext& g = *GImGui;
  10099     if (!g.LogEnabled)
  10100         return;
  10101 
  10102     LogTextV(g, fmt, args);
  10103 }
  10104 
  10105 // Internal version that takes a position to decide on newline placement and pad items according to their depth.
  10106 // We split text into individual lines to add current tree level padding
  10107 // FIXME: This code is a little complicated perhaps, considering simplifying the whole system.
  10108 void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)
  10109 {
  10110     ImGuiContext& g = *GImGui;
  10111     ImGuiWindow* window = g.CurrentWindow;
  10112 
  10113     const char* prefix = g.LogNextPrefix;
  10114     const char* suffix = g.LogNextSuffix;
  10115     g.LogNextPrefix = g.LogNextSuffix = NULL;
  10116 
  10117     if (!text_end)
  10118         text_end = FindRenderedTextEnd(text, text_end);
  10119 
  10120     const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1);
  10121     if (ref_pos)
  10122         g.LogLinePosY = ref_pos->y;
  10123     if (log_new_line)
  10124     {
  10125         LogText(IM_NEWLINE);
  10126         g.LogLineFirstItem = true;
  10127     }
  10128 
  10129     if (prefix)
  10130         LogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure "##" are included here.
  10131 
  10132     // Re-adjust padding if we have popped out of our starting depth
  10133     if (g.LogDepthRef > window->DC.TreeDepth)
  10134         g.LogDepthRef = window->DC.TreeDepth;
  10135     const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef);
  10136 
  10137     const char* text_remaining = text;
  10138     for (;;)
  10139     {
  10140         // Split the string. Each new line (after a '\n') is followed by indentation corresponding to the current depth of our log entry.
  10141         // We don't add a trailing \n yet to allow a subsequent item on the same line to be captured.
  10142         const char* line_start = text_remaining;
  10143         const char* line_end = ImStreolRange(line_start, text_end);
  10144         const bool is_last_line = (line_end == text_end);
  10145         if (line_start != line_end || !is_last_line)
  10146         {
  10147             const int line_length = (int)(line_end - line_start);
  10148             const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1;
  10149             LogText("%*s%.*s", indentation, "", line_length, line_start);
  10150             g.LogLineFirstItem = false;
  10151             if (*line_end == '\n')
  10152             {
  10153                 LogText(IM_NEWLINE);
  10154                 g.LogLineFirstItem = true;
  10155             }
  10156         }
  10157         if (is_last_line)
  10158             break;
  10159         text_remaining = line_end + 1;
  10160     }
  10161 
  10162     if (suffix)
  10163         LogRenderedText(ref_pos, suffix, suffix + strlen(suffix));
  10164 }
  10165 
  10166 // Start logging/capturing text output
  10167 void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)
  10168 {
  10169     ImGuiContext& g = *GImGui;
  10170     ImGuiWindow* window = g.CurrentWindow;
  10171     IM_ASSERT(g.LogEnabled == false);
  10172     IM_ASSERT(g.LogFile == NULL);
  10173     IM_ASSERT(g.LogBuffer.empty());
  10174     g.LogEnabled = true;
  10175     g.LogType = type;
  10176     g.LogNextPrefix = g.LogNextSuffix = NULL;
  10177     g.LogDepthRef = window->DC.TreeDepth;
  10178     g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault);
  10179     g.LogLinePosY = FLT_MAX;
  10180     g.LogLineFirstItem = true;
  10181 }
  10182 
  10183 // Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText)
  10184 void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix)
  10185 {
  10186     ImGuiContext& g = *GImGui;
  10187     g.LogNextPrefix = prefix;
  10188     g.LogNextSuffix = suffix;
  10189 }
  10190 
  10191 void ImGui::LogToTTY(int auto_open_depth)
  10192 {
  10193     ImGuiContext& g = *GImGui;
  10194     if (g.LogEnabled)
  10195         return;
  10196     IM_UNUSED(auto_open_depth);
  10197 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS
  10198     LogBegin(ImGuiLogType_TTY, auto_open_depth);
  10199     g.LogFile = stdout;
  10200 #endif
  10201 }
  10202 
  10203 // Start logging/capturing text output to given file
  10204 void ImGui::LogToFile(int auto_open_depth, const char* filename)
  10205 {
  10206     ImGuiContext& g = *GImGui;
  10207     if (g.LogEnabled)
  10208         return;
  10209 
  10210     // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still
  10211     // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE.
  10212     // By opening the file in binary mode "ab" we have consistent output everywhere.
  10213     if (!filename)
  10214         filename = g.IO.LogFilename;
  10215     if (!filename || !filename[0])
  10216         return;
  10217     ImFileHandle f = ImFileOpen(filename, "ab");
  10218     if (!f)
  10219     {
  10220         IM_ASSERT(0);
  10221         return;
  10222     }
  10223 
  10224     LogBegin(ImGuiLogType_File, auto_open_depth);
  10225     g.LogFile = f;
  10226 }
  10227 
  10228 // Start logging/capturing text output to clipboard
  10229 void ImGui::LogToClipboard(int auto_open_depth)
  10230 {
  10231     ImGuiContext& g = *GImGui;
  10232     if (g.LogEnabled)
  10233         return;
  10234     LogBegin(ImGuiLogType_Clipboard, auto_open_depth);
  10235 }
  10236 
  10237 void ImGui::LogToBuffer(int auto_open_depth)
  10238 {
  10239     ImGuiContext& g = *GImGui;
  10240     if (g.LogEnabled)
  10241         return;
  10242     LogBegin(ImGuiLogType_Buffer, auto_open_depth);
  10243 }
  10244 
  10245 void ImGui::LogFinish()
  10246 {
  10247     ImGuiContext& g = *GImGui;
  10248     if (!g.LogEnabled)
  10249         return;
  10250 
  10251     LogText(IM_NEWLINE);
  10252     switch (g.LogType)
  10253     {
  10254     case ImGuiLogType_TTY:
  10255 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS
  10256         fflush(g.LogFile);
  10257 #endif
  10258         break;
  10259     case ImGuiLogType_File:
  10260         ImFileClose(g.LogFile);
  10261         break;
  10262     case ImGuiLogType_Buffer:
  10263         break;
  10264     case ImGuiLogType_Clipboard:
  10265         if (!g.LogBuffer.empty())
  10266             SetClipboardText(g.LogBuffer.begin());
  10267         break;
  10268     case ImGuiLogType_None:
  10269         IM_ASSERT(0);
  10270         break;
  10271     }
  10272 
  10273     g.LogEnabled = false;
  10274     g.LogType = ImGuiLogType_None;
  10275     g.LogFile = NULL;
  10276     g.LogBuffer.clear();
  10277 }
  10278 
  10279 // Helper to display logging buttons
  10280 // FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!)
  10281 void ImGui::LogButtons()
  10282 {
  10283     ImGuiContext& g = *GImGui;
  10284 
  10285     PushID("LogButtons");
  10286 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS
  10287     const bool log_to_tty = Button("Log To TTY"); SameLine();
  10288 #else
  10289     const bool log_to_tty = false;
  10290 #endif
  10291     const bool log_to_file = Button("Log To File"); SameLine();
  10292     const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
  10293     PushAllowKeyboardFocus(false);
  10294     SetNextItemWidth(80.0f);
  10295     SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL);
  10296     PopAllowKeyboardFocus();
  10297     PopID();
  10298 
  10299     // Start logging at the end of the function so that the buttons don't appear in the log
  10300     if (log_to_tty)
  10301         LogToTTY();
  10302     if (log_to_file)
  10303         LogToFile();
  10304     if (log_to_clipboard)
  10305         LogToClipboard();
  10306 }
  10307 
  10308 
  10309 //-----------------------------------------------------------------------------
  10310 // [SECTION] SETTINGS
  10311 //-----------------------------------------------------------------------------
  10312 // - UpdateSettings() [Internal]
  10313 // - MarkIniSettingsDirty() [Internal]
  10314 // - CreateNewWindowSettings() [Internal]
  10315 // - FindWindowSettings() [Internal]
  10316 // - FindOrCreateWindowSettings() [Internal]
  10317 // - FindSettingsHandler() [Internal]
  10318 // - ClearIniSettings() [Internal]
  10319 // - LoadIniSettingsFromDisk()
  10320 // - LoadIniSettingsFromMemory()
  10321 // - SaveIniSettingsToDisk()
  10322 // - SaveIniSettingsToMemory()
  10323 // - WindowSettingsHandler_***() [Internal]
  10324 //-----------------------------------------------------------------------------
  10325 
  10326 // Called by NewFrame()
  10327 void ImGui::UpdateSettings()
  10328 {
  10329     // Load settings on first frame (if not explicitly loaded manually before)
  10330     ImGuiContext& g = *GImGui;
  10331     if (!g.SettingsLoaded)
  10332     {
  10333         IM_ASSERT(g.SettingsWindows.empty());
  10334         if (g.IO.IniFilename)
  10335             LoadIniSettingsFromDisk(g.IO.IniFilename);
  10336         g.SettingsLoaded = true;
  10337     }
  10338 
  10339     // Save settings (with a delay after the last modification, so we don't spam disk too much)
  10340     if (g.SettingsDirtyTimer > 0.0f)
  10341     {
  10342         g.SettingsDirtyTimer -= g.IO.DeltaTime;
  10343         if (g.SettingsDirtyTimer <= 0.0f)
  10344         {
  10345             if (g.IO.IniFilename != NULL)
  10346                 SaveIniSettingsToDisk(g.IO.IniFilename);
  10347             else
  10348                 g.IO.WantSaveIniSettings = true;  // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
  10349             g.SettingsDirtyTimer = 0.0f;
  10350         }
  10351     }
  10352 }
  10353 
  10354 void ImGui::MarkIniSettingsDirty()
  10355 {
  10356     ImGuiContext& g = *GImGui;
  10357     if (g.SettingsDirtyTimer <= 0.0f)
  10358         g.SettingsDirtyTimer = g.IO.IniSavingRate;
  10359 }
  10360 
  10361 void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
  10362 {
  10363     ImGuiContext& g = *GImGui;
  10364     if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
  10365         if (g.SettingsDirtyTimer <= 0.0f)
  10366             g.SettingsDirtyTimer = g.IO.IniSavingRate;
  10367 }
  10368 
  10369 ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
  10370 {
  10371     ImGuiContext& g = *GImGui;
  10372 
  10373 #if !IMGUI_DEBUG_INI_SETTINGS
  10374     // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
  10375     // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
  10376     if (const char* p = strstr(name, "###"))
  10377         name = p;
  10378 #endif
  10379     const size_t name_len = strlen(name);
  10380 
  10381     // Allocate chunk
  10382     const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
  10383     ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
  10384     IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
  10385     settings->ID = ImHashStr(name, name_len);
  10386     memcpy(settings->GetName(), name, name_len + 1);   // Store with zero terminator
  10387 
  10388     return settings;
  10389 }
  10390 
  10391 ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
  10392 {
  10393     ImGuiContext& g = *GImGui;
  10394     for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
  10395         if (settings->ID == id)
  10396             return settings;
  10397     return NULL;
  10398 }
  10399 
  10400 ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
  10401 {
  10402     if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name)))
  10403         return settings;
  10404     return CreateNewWindowSettings(name);
  10405 }
  10406 
  10407 ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
  10408 {
  10409     ImGuiContext& g = *GImGui;
  10410     const ImGuiID type_hash = ImHashStr(type_name);
  10411     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
  10412         if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
  10413             return &g.SettingsHandlers[handler_n];
  10414     return NULL;
  10415 }
  10416 
  10417 void ImGui::ClearIniSettings()
  10418 {
  10419     ImGuiContext& g = *GImGui;
  10420     g.SettingsIniData.clear();
  10421     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
  10422         if (g.SettingsHandlers[handler_n].ClearAllFn)
  10423             g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]);
  10424 }
  10425 
  10426 void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
  10427 {
  10428     size_t file_data_size = 0;
  10429     char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
  10430     if (!file_data)
  10431         return;
  10432     LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
  10433     IM_FREE(file_data);
  10434 }
  10435 
  10436 // Zero-tolerance, no error reporting, cheap .ini parsing
  10437 void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
  10438 {
  10439     ImGuiContext& g = *GImGui;
  10440     IM_ASSERT(g.Initialized);
  10441     //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()");
  10442     //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
  10443 
  10444     // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
  10445     // 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..
  10446     if (ini_size == 0)
  10447         ini_size = strlen(ini_data);
  10448     g.SettingsIniData.Buf.resize((int)ini_size + 1);
  10449     char* const buf = g.SettingsIniData.Buf.Data;
  10450     char* const buf_end = buf + ini_size;
  10451     memcpy(buf, ini_data, ini_size);
  10452     buf_end[0] = 0;
  10453 
  10454     // Call pre-read handlers
  10455     // Some types will clear their data (e.g. dock information) some types will allow merge/override (window)
  10456     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
  10457         if (g.SettingsHandlers[handler_n].ReadInitFn)
  10458             g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]);
  10459 
  10460     void* entry_data = NULL;
  10461     ImGuiSettingsHandler* entry_handler = NULL;
  10462 
  10463     char* line_end = NULL;
  10464     for (char* line = buf; line < buf_end; line = line_end + 1)
  10465     {
  10466         // Skip new lines markers, then find end of the line
  10467         while (*line == '\n' || *line == '\r')
  10468             line++;
  10469         line_end = line;
  10470         while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
  10471             line_end++;
  10472         line_end[0] = 0;
  10473         if (line[0] == ';')
  10474             continue;
  10475         if (line[0] == '[' && line_end > line && line_end[-1] == ']')
  10476         {
  10477             // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
  10478             line_end[-1] = 0;
  10479             const char* name_end = line_end - 1;
  10480             const char* type_start = line + 1;
  10481             char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');
  10482             const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
  10483             if (!type_end || !name_start)
  10484                 continue;
  10485             *type_end = 0; // Overwrite first ']'
  10486             name_start++;  // Skip second '['
  10487             entry_handler = FindSettingsHandler(type_start);
  10488             entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
  10489         }
  10490         else if (entry_handler != NULL && entry_data != NULL)
  10491         {
  10492             // Let type handler parse the line
  10493             entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
  10494         }
  10495     }
  10496     g.SettingsLoaded = true;
  10497 
  10498     // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary)
  10499     memcpy(buf, ini_data, ini_size);
  10500 
  10501     // Call post-read handlers
  10502     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
  10503         if (g.SettingsHandlers[handler_n].ApplyAllFn)
  10504             g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]);
  10505 }
  10506 
  10507 void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
  10508 {
  10509     ImGuiContext& g = *GImGui;
  10510     g.SettingsDirtyTimer = 0.0f;
  10511     if (!ini_filename)
  10512         return;
  10513 
  10514     size_t ini_data_size = 0;
  10515     const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
  10516     ImFileHandle f = ImFileOpen(ini_filename, "wt");
  10517     if (!f)
  10518         return;
  10519     ImFileWrite(ini_data, sizeof(char), ini_data_size, f);
  10520     ImFileClose(f);
  10521 }
  10522 
  10523 // Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
  10524 const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
  10525 {
  10526     ImGuiContext& g = *GImGui;
  10527     g.SettingsDirtyTimer = 0.0f;
  10528     g.SettingsIniData.Buf.resize(0);
  10529     g.SettingsIniData.Buf.push_back(0);
  10530     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
  10531     {
  10532         ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
  10533         handler->WriteAllFn(&g, handler, &g.SettingsIniData);
  10534     }
  10535     if (out_size)
  10536         *out_size = (size_t)g.SettingsIniData.size();
  10537     return g.SettingsIniData.c_str();
  10538 }
  10539 
  10540 static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
  10541 {
  10542     ImGuiContext& g = *ctx;
  10543     for (int i = 0; i != g.Windows.Size; i++)
  10544         g.Windows[i]->SettingsOffset = -1;
  10545     g.SettingsWindows.clear();
  10546 }
  10547 
  10548 static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
  10549 {
  10550     ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name);
  10551     ImGuiID id = settings->ID;
  10552     *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry
  10553     settings->ID = id;
  10554     settings->WantApply = true;
  10555     return (void*)settings;
  10556 }
  10557 
  10558 static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
  10559 {
  10560     ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
  10561     int x, y;
  10562     int i;
  10563     if (sscanf(line, "Pos=%i,%i", &x, &y) == 2)         { settings->Pos = ImVec2ih((short)x, (short)y); }
  10564     else if (sscanf(line, "Size=%i,%i", &x, &y) == 2)   { settings->Size = ImVec2ih((short)x, (short)y); }
  10565     else if (sscanf(line, "Collapsed=%d", &i) == 1)     { settings->Collapsed = (i != 0); }
  10566 }
  10567 
  10568 // Apply to existing windows (if any)
  10569 static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
  10570 {
  10571     ImGuiContext& g = *ctx;
  10572     for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
  10573         if (settings->WantApply)
  10574         {
  10575             if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID))
  10576                 ApplyWindowSettings(window, settings);
  10577             settings->WantApply = false;
  10578         }
  10579 }
  10580 
  10581 static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
  10582 {
  10583     // Gather data from windows that were active during this session
  10584     // (if a window wasn't opened in this session we preserve its settings)
  10585     ImGuiContext& g = *ctx;
  10586     for (int i = 0; i != g.Windows.Size; i++)
  10587     {
  10588         ImGuiWindow* window = g.Windows[i];
  10589         if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
  10590             continue;
  10591 
  10592         ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID);
  10593         if (!settings)
  10594         {
  10595             settings = ImGui::CreateNewWindowSettings(window->Name);
  10596             window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
  10597         }
  10598         IM_ASSERT(settings->ID == window->ID);
  10599         settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y);
  10600         settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y);
  10601         settings->Collapsed = window->Collapsed;
  10602     }
  10603 
  10604     // Write to text buffer
  10605     buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
  10606     for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
  10607     {
  10608         const char* settings_name = settings->GetName();
  10609         buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
  10610         buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
  10611         buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
  10612         buf->appendf("Collapsed=%d\n", settings->Collapsed);
  10613         buf->append("\n");
  10614     }
  10615 }
  10616 
  10617 
  10618 //-----------------------------------------------------------------------------
  10619 // [SECTION] VIEWPORTS, PLATFORM WINDOWS
  10620 //-----------------------------------------------------------------------------
  10621 // - GetMainViewport()
  10622 // - UpdateViewportsNewFrame() [Internal]
  10623 // (this section is more complete in the 'docking' branch)
  10624 //-----------------------------------------------------------------------------
  10625 
  10626 ImGuiViewport* ImGui::GetMainViewport()
  10627 {
  10628     ImGuiContext& g = *GImGui;
  10629     return g.Viewports[0];
  10630 }
  10631 
  10632 // Update viewports and monitor infos
  10633 static void ImGui::UpdateViewportsNewFrame()
  10634 {
  10635     ImGuiContext& g = *GImGui;
  10636     IM_ASSERT(g.Viewports.Size == 1);
  10637 
  10638     // Update main viewport with current platform position.
  10639     // FIXME-VIEWPORT: Size is driven by backend/user code for backward-compatibility but we should aim to make this more consistent.
  10640     ImGuiViewportP* main_viewport = g.Viewports[0];
  10641     main_viewport->Flags = ImGuiViewportFlags_IsPlatformWindow | ImGuiViewportFlags_OwnedByApp;
  10642     main_viewport->Pos = ImVec2(0.0f, 0.0f);
  10643     main_viewport->Size = g.IO.DisplaySize;
  10644 
  10645     for (int n = 0; n < g.Viewports.Size; n++)
  10646     {
  10647         ImGuiViewportP* viewport = g.Viewports[n];
  10648 
  10649         // Lock down space taken by menu bars and status bars, reset the offset for fucntions like BeginMainMenuBar() to alter them again.
  10650         viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin;
  10651         viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax;
  10652         viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f);
  10653         viewport->UpdateWorkRect();
  10654     }
  10655 }
  10656 
  10657 //-----------------------------------------------------------------------------
  10658 // [SECTION] DOCKING
  10659 //-----------------------------------------------------------------------------
  10660 
  10661 // (this section is filled in the 'docking' branch)
  10662 
  10663 
  10664 //-----------------------------------------------------------------------------
  10665 // [SECTION] PLATFORM DEPENDENT HELPERS
  10666 //-----------------------------------------------------------------------------
  10667 
  10668 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
  10669 
  10670 #ifdef _MSC_VER
  10671 #pragma comment(lib, "user32")
  10672 #pragma comment(lib, "kernel32")
  10673 #endif
  10674 
  10675 // Win32 clipboard implementation
  10676 // We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown()
  10677 static const char* GetClipboardTextFn_DefaultImpl(void*)
  10678 {
  10679     ImGuiContext& g = *GImGui;
  10680     g.ClipboardHandlerData.clear();
  10681     if (!::OpenClipboard(NULL))
  10682         return NULL;
  10683     HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
  10684     if (wbuf_handle == NULL)
  10685     {
  10686         ::CloseClipboard();
  10687         return NULL;
  10688     }
  10689     if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
  10690     {
  10691         int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
  10692         g.ClipboardHandlerData.resize(buf_len);
  10693         ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
  10694     }
  10695     ::GlobalUnlock(wbuf_handle);
  10696     ::CloseClipboard();
  10697     return g.ClipboardHandlerData.Data;
  10698 }
  10699 
  10700 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
  10701 {
  10702     if (!::OpenClipboard(NULL))
  10703         return;
  10704     const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
  10705     HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
  10706     if (wbuf_handle == NULL)
  10707     {
  10708         ::CloseClipboard();
  10709         return;
  10710     }
  10711     WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
  10712     ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
  10713     ::GlobalUnlock(wbuf_handle);
  10714     ::EmptyClipboard();
  10715     if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
  10716         ::GlobalFree(wbuf_handle);
  10717     ::CloseClipboard();
  10718 }
  10719 
  10720 #elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
  10721 
  10722 #include <Carbon/Carbon.h>  // Use old API to avoid need for separate .mm file
  10723 static PasteboardRef main_clipboard = 0;
  10724 
  10725 // OSX clipboard implementation
  10726 // If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!
  10727 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
  10728 {
  10729     if (!main_clipboard)
  10730         PasteboardCreate(kPasteboardClipboard, &main_clipboard);
  10731     PasteboardClear(main_clipboard);
  10732     CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));
  10733     if (cf_data)
  10734     {
  10735         PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
  10736         CFRelease(cf_data);
  10737     }
  10738 }
  10739 
  10740 static const char* GetClipboardTextFn_DefaultImpl(void*)
  10741 {
  10742     if (!main_clipboard)
  10743         PasteboardCreate(kPasteboardClipboard, &main_clipboard);
  10744     PasteboardSynchronize(main_clipboard);
  10745 
  10746     ItemCount item_count = 0;
  10747     PasteboardGetItemCount(main_clipboard, &item_count);
  10748     for (ItemCount i = 0; i < item_count; i++)
  10749     {
  10750         PasteboardItemID item_id = 0;
  10751         PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
  10752         CFArrayRef flavor_type_array = 0;
  10753         PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
  10754         for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
  10755         {
  10756             CFDataRef cf_data;
  10757             if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
  10758             {
  10759                 ImGuiContext& g = *GImGui;
  10760                 g.ClipboardHandlerData.clear();
  10761                 int length = (int)CFDataGetLength(cf_data);
  10762                 g.ClipboardHandlerData.resize(length + 1);
  10763                 CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data);
  10764                 g.ClipboardHandlerData[length] = 0;
  10765                 CFRelease(cf_data);
  10766                 return g.ClipboardHandlerData.Data;
  10767             }
  10768         }
  10769     }
  10770     return NULL;
  10771 }
  10772 
  10773 #else
  10774 
  10775 // Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
  10776 static const char* GetClipboardTextFn_DefaultImpl(void*)
  10777 {
  10778     ImGuiContext& g = *GImGui;
  10779     return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();
  10780 }
  10781 
  10782 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
  10783 {
  10784     ImGuiContext& g = *GImGui;
  10785     g.ClipboardHandlerData.clear();
  10786     const char* text_end = text + strlen(text);
  10787     g.ClipboardHandlerData.resize((int)(text_end - text) + 1);
  10788     memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text));
  10789     g.ClipboardHandlerData[(int)(text_end - text)] = 0;
  10790 }
  10791 
  10792 #endif
  10793 
  10794 // Win32 API IME support (for Asian languages, etc.)
  10795 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
  10796 
  10797 #include <imm.h>
  10798 #ifdef _MSC_VER
  10799 #pragma comment(lib, "imm32")
  10800 #endif
  10801 
  10802 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
  10803 {
  10804     // Notify OS Input Method Editor of text input position
  10805     ImGuiIO& io = ImGui::GetIO();
  10806     if (HWND hwnd = (HWND)io.ImeWindowHandle)
  10807         if (HIMC himc = ::ImmGetContext(hwnd))
  10808         {
  10809             COMPOSITIONFORM cf;
  10810             cf.ptCurrentPos.x = x;
  10811             cf.ptCurrentPos.y = y;
  10812             cf.dwStyle = CFS_FORCE_POSITION;
  10813             ::ImmSetCompositionWindow(himc, &cf);
  10814             ::ImmReleaseContext(hwnd, himc);
  10815         }
  10816 }
  10817 
  10818 #else
  10819 
  10820 static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
  10821 
  10822 #endif
  10823 
  10824 //-----------------------------------------------------------------------------
  10825 // [SECTION] METRICS/DEBUGGER WINDOW
  10826 //-----------------------------------------------------------------------------
  10827 // - RenderViewportThumbnail() [Internal]
  10828 // - RenderViewportsThumbnails() [Internal]
  10829 // - MetricsHelpMarker() [Internal]
  10830 // - ShowMetricsWindow()
  10831 // - DebugNodeColumns() [Internal]
  10832 // - DebugNodeDrawList() [Internal]
  10833 // - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal]
  10834 // - DebugNodeStorage() [Internal]
  10835 // - DebugNodeTabBar() [Internal]
  10836 // - DebugNodeViewport() [Internal]
  10837 // - DebugNodeWindow() [Internal]
  10838 // - DebugNodeWindowSettings() [Internal]
  10839 // - DebugNodeWindowsList() [Internal]
  10840 //-----------------------------------------------------------------------------
  10841 
  10842 #ifndef IMGUI_DISABLE_METRICS_WINDOW
  10843 
  10844 void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb)
  10845 {
  10846     ImGuiContext& g = *GImGui;
  10847     ImGuiWindow* window = g.CurrentWindow;
  10848 
  10849     ImVec2 scale = bb.GetSize() / viewport->Size;
  10850     ImVec2 off = bb.Min - viewport->Pos * scale;
  10851     float alpha_mul = 1.0f;
  10852     window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f));
  10853     for (int i = 0; i != g.Windows.Size; i++)
  10854     {
  10855         ImGuiWindow* thumb_window = g.Windows[i];
  10856         if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow))
  10857             continue;
  10858 
  10859         ImRect thumb_r = thumb_window->Rect();
  10860         ImRect title_r = thumb_window->TitleBarRect();
  10861         thumb_r = ImRect(ImFloor(off + thumb_r.Min * scale), ImFloor(off +  thumb_r.Max * scale));
  10862         title_r = ImRect(ImFloor(off + title_r.Min * scale), ImFloor(off +  ImVec2(title_r.Max.x, title_r.Min.y) * scale) + ImVec2(0,5)); // Exaggerate title bar height
  10863         thumb_r.ClipWithFull(bb);
  10864         title_r.ClipWithFull(bb);
  10865         const bool window_is_focused = (g.NavWindow && thumb_window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight);
  10866         window->DrawList->AddRectFilled(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_WindowBg, alpha_mul));
  10867         window->DrawList->AddRectFilled(title_r.Min, title_r.Max, GetColorU32(window_is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg, alpha_mul));
  10868         window->DrawList->AddRect(thumb_r.Min, thumb_r.Max, GetColorU32(ImGuiCol_Border, alpha_mul));
  10869         window->DrawList->AddText(g.Font, g.FontSize * 1.0f, title_r.Min, GetColorU32(ImGuiCol_Text, alpha_mul), thumb_window->Name, FindRenderedTextEnd(thumb_window->Name));
  10870     }
  10871     draw_list->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul));
  10872 }
  10873 
  10874 static void RenderViewportsThumbnails()
  10875 {
  10876     ImGuiContext& g = *GImGui;
  10877     ImGuiWindow* window = g.CurrentWindow;
  10878 
  10879     // We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports.
  10880     float SCALE = 1.0f / 8.0f;
  10881     ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
  10882     for (int n = 0; n < g.Viewports.Size; n++)
  10883         bb_full.Add(g.Viewports[n]->GetMainRect());
  10884     ImVec2 p = window->DC.CursorPos;
  10885     ImVec2 off = p - bb_full.Min * SCALE;
  10886     for (int n = 0; n < g.Viewports.Size; n++)
  10887     {
  10888         ImGuiViewportP* viewport = g.Viewports[n];
  10889         ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE);
  10890         ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb);
  10891     }
  10892     ImGui::Dummy(bb_full.GetSize() * SCALE);
  10893 }
  10894 
  10895 // Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
  10896 static void MetricsHelpMarker(const char* desc)
  10897 {
  10898     ImGui::TextDisabled("(?)");
  10899     if (ImGui::IsItemHovered())
  10900     {
  10901         ImGui::BeginTooltip();
  10902         ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
  10903         ImGui::TextUnformatted(desc);
  10904         ImGui::PopTextWrapPos();
  10905         ImGui::EndTooltip();
  10906     }
  10907 }
  10908 
  10909 #ifndef IMGUI_DISABLE_DEMO_WINDOWS
  10910 namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); }
  10911 #endif
  10912 
  10913 void ImGui::ShowMetricsWindow(bool* p_open)
  10914 {
  10915     if (!Begin("Dear ImGui Metrics/Debugger", p_open))
  10916     {
  10917         End();
  10918         return;
  10919     }
  10920 
  10921     ImGuiContext& g = *GImGui;
  10922     ImGuiIO& io = g.IO;
  10923     ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
  10924 
  10925     // Basic info
  10926     Text("Dear ImGui %s", GetVersion());
  10927     Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
  10928     Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
  10929     Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows);
  10930     Text("%d active allocations", io.MetricsActiveAllocations);
  10931     //SameLine(); if (SmallButton("GC")) { g.GcCompactAll = true; }
  10932 
  10933     Separator();
  10934 
  10935     // Debugging enums
  10936     enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentIdeal, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type
  10937     const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentIdeal", "ContentRegionRect" };
  10938     enum { TRT_OuterRect, TRT_InnerRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsWorkRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type
  10939     const char* trt_rects_names[TRT_Count] = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsWorkRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" };
  10940     if (cfg->ShowWindowsRectsType < 0)
  10941         cfg->ShowWindowsRectsType = WRT_WorkRect;
  10942     if (cfg->ShowTablesRectsType < 0)
  10943         cfg->ShowTablesRectsType = TRT_WorkRect;
  10944 
  10945     struct Funcs
  10946     {
  10947         static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)
  10948         {
  10949             if (rect_type == TRT_OuterRect)                     { return table->OuterRect; }
  10950             else if (rect_type == TRT_InnerRect)                { return table->InnerRect; }
  10951             else if (rect_type == TRT_WorkRect)                 { return table->WorkRect; }
  10952             else if (rect_type == TRT_HostClipRect)             { return table->HostClipRect; }
  10953             else if (rect_type == TRT_InnerClipRect)            { return table->InnerClipRect; }
  10954             else if (rect_type == TRT_BackgroundClipRect)       { return table->BgClipRect; }
  10955             else if (rect_type == TRT_ColumnsRect)              { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table->LastOuterHeight); }
  10956             else if (rect_type == TRT_ColumnsWorkRect)          { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); }
  10957             else if (rect_type == TRT_ColumnsClipRect)          { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; }
  10958             else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table->LastFirstRowHeight); } // Note: y1/y2 not always accurate
  10959             else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table->LastFirstRowHeight); }
  10960             else if (rect_type == TRT_ColumnsContentFrozen)     { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table->LastFirstRowHeight); }
  10961             else if (rect_type == TRT_ColumnsContentUnfrozen)   { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table->LastFirstRowHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }
  10962             IM_ASSERT(0);
  10963             return ImRect();
  10964         }
  10965 
  10966         static ImRect GetWindowRect(ImGuiWindow* window, int rect_type)
  10967         {
  10968             if (rect_type == WRT_OuterRect)                 { return window->Rect(); }
  10969             else if (rect_type == WRT_OuterRectClipped)     { return window->OuterRectClipped; }
  10970             else if (rect_type == WRT_InnerRect)            { return window->InnerRect; }
  10971             else if (rect_type == WRT_InnerClipRect)        { return window->InnerClipRect; }
  10972             else if (rect_type == WRT_WorkRect)             { return window->WorkRect; }
  10973             else if (rect_type == WRT_Content)       { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
  10974             else if (rect_type == WRT_ContentIdeal)         { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSizeIdeal); }
  10975             else if (rect_type == WRT_ContentRegionRect)    { return window->ContentRegionRect; }
  10976             IM_ASSERT(0);
  10977             return ImRect();
  10978         }
  10979     };
  10980 
  10981     // Tools
  10982     if (TreeNode("Tools"))
  10983     {
  10984         // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
  10985         if (Button("Item Picker.."))
  10986             DebugStartItemPicker();
  10987         SameLine();
  10988         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.");
  10989 
  10990         Checkbox("Show windows begin order", &cfg->ShowWindowsBeginOrder);
  10991         Checkbox("Show windows rectangles", &cfg->ShowWindowsRects);
  10992         SameLine();
  10993         SetNextItemWidth(GetFontSize() * 12);
  10994         cfg->ShowWindowsRects |= Combo("##show_windows_rect_type", &cfg->ShowWindowsRectsType, wrt_rects_names, WRT_Count, WRT_Count);
  10995         if (cfg->ShowWindowsRects && g.NavWindow != NULL)
  10996         {
  10997             BulletText("'%s':", g.NavWindow->Name);
  10998             Indent();
  10999             for (int rect_n = 0; rect_n < WRT_Count; rect_n++)
  11000             {
  11001                 ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n);
  11002                 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]);
  11003             }
  11004             Unindent();
  11005         }
  11006         Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
  11007         Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
  11008 
  11009         Checkbox("Show tables rectangles", &cfg->ShowTablesRects);
  11010         SameLine();
  11011         SetNextItemWidth(GetFontSize() * 12);
  11012         cfg->ShowTablesRects |= Combo("##show_table_rects_type", &cfg->ShowTablesRectsType, trt_rects_names, TRT_Count, TRT_Count);
  11013         if (cfg->ShowTablesRects && g.NavWindow != NULL)
  11014         {
  11015             for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
  11016             {
  11017                 ImGuiTable* table = g.Tables.GetByIndex(table_n);
  11018                 if (table->LastFrameActive < g.FrameCount - 1 || (table->OuterWindow != g.NavWindow && table->InnerWindow != g.NavWindow))
  11019                     continue;
  11020 
  11021                 BulletText("Table 0x%08X (%d columns, in '%s')", table->ID, table->ColumnsCount, table->OuterWindow->Name);
  11022                 if (IsItemHovered())
  11023                     GetForegroundDrawList()->AddRect(table->OuterRect.Min - ImVec2(1, 1), table->OuterRect.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
  11024                 Indent();
  11025                 char buf[128];
  11026                 for (int rect_n = 0; rect_n < TRT_Count; rect_n++)
  11027                 {
  11028                     if (rect_n >= TRT_ColumnsRect)
  11029                     {
  11030                         if (rect_n != TRT_ColumnsRect && rect_n != TRT_ColumnsClipRect)
  11031                             continue;
  11032                         for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
  11033                         {
  11034                             ImRect r = Funcs::GetTableRect(table, rect_n, column_n);
  11035                             ImFormatString(buf, IM_ARRAYSIZE(buf), "(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) Col %d %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), column_n, trt_rects_names[rect_n]);
  11036                             Selectable(buf);
  11037                             if (IsItemHovered())
  11038                                 GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
  11039                         }
  11040                     }
  11041                     else
  11042                     {
  11043                         ImRect r = Funcs::GetTableRect(table, rect_n, -1);
  11044                         ImFormatString(buf, IM_ARRAYSIZE(buf), "(%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(), trt_rects_names[rect_n]);
  11045                         Selectable(buf);
  11046                         if (IsItemHovered())
  11047                             GetForegroundDrawList()->AddRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255), 0.0f, 0, 2.0f);
  11048                     }
  11049                 }
  11050                 Unindent();
  11051             }
  11052         }
  11053 
  11054         TreePop();
  11055     }
  11056 
  11057     // Windows
  11058     DebugNodeWindowsList(&g.Windows, "Windows");
  11059     //DebugNodeWindowsList(&g.WindowsFocusOrder, "WindowsFocusOrder");
  11060 
  11061     // DrawLists
  11062     int drawlist_count = 0;
  11063     for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++)
  11064         drawlist_count += g.Viewports[viewport_i]->DrawDataBuilder.GetDrawListCount();
  11065     if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count))
  11066     {
  11067         for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++)
  11068         {
  11069             ImGuiViewportP* viewport = g.Viewports[viewport_i];
  11070             for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++)
  11071                 for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++)
  11072                     DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList");
  11073         }
  11074         TreePop();
  11075     }
  11076 
  11077     // Viewports
  11078     if (TreeNode("Viewports", "Viewports (%d)", g.Viewports.Size))
  11079     {
  11080         Indent(GetTreeNodeToLabelSpacing());
  11081         RenderViewportsThumbnails();
  11082         Unindent(GetTreeNodeToLabelSpacing());
  11083         for (int i = 0; i < g.Viewports.Size; i++)
  11084             DebugNodeViewport(g.Viewports[i]);
  11085         TreePop();
  11086     }
  11087 
  11088     // Details for Popups
  11089     if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
  11090     {
  11091         for (int i = 0; i < g.OpenPopupStack.Size; i++)
  11092         {
  11093             ImGuiWindow* window = g.OpenPopupStack[i].Window;
  11094             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" : "");
  11095         }
  11096         TreePop();
  11097     }
  11098 
  11099     // Details for TabBars
  11100     if (TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
  11101     {
  11102         for (int n = 0; n < g.TabBars.GetSize(); n++)
  11103             DebugNodeTabBar(g.TabBars.GetByIndex(n), "TabBar");
  11104         TreePop();
  11105     }
  11106 
  11107     // Details for Tables
  11108     if (TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
  11109     {
  11110         for (int n = 0; n < g.Tables.GetSize(); n++)
  11111             DebugNodeTable(g.Tables.GetByIndex(n));
  11112         TreePop();
  11113     }
  11114 
  11115     // Details for Fonts
  11116 #ifndef IMGUI_DISABLE_DEMO_WINDOWS
  11117     ImFontAtlas* atlas = g.IO.Fonts;
  11118     if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size))
  11119     {
  11120         ShowFontAtlas(atlas);
  11121         TreePop();
  11122     }
  11123 #endif
  11124 
  11125     // Details for Docking
  11126 #ifdef IMGUI_HAS_DOCK
  11127     if (TreeNode("Docking"))
  11128     {
  11129         TreePop();
  11130     }
  11131 #endif // #ifdef IMGUI_HAS_DOCK
  11132 
  11133     // Settings
  11134     if (TreeNode("Settings"))
  11135     {
  11136         if (SmallButton("Clear"))
  11137             ClearIniSettings();
  11138         SameLine();
  11139         if (SmallButton("Save to memory"))
  11140             SaveIniSettingsToMemory();
  11141         SameLine();
  11142         if (SmallButton("Save to disk"))
  11143             SaveIniSettingsToDisk(g.IO.IniFilename);
  11144         SameLine();
  11145         if (g.IO.IniFilename)
  11146             Text("\"%s\"", g.IO.IniFilename);
  11147         else
  11148             TextUnformatted("<NULL>");
  11149         Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
  11150         if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
  11151         {
  11152             for (int n = 0; n < g.SettingsHandlers.Size; n++)
  11153                 BulletText("%s", g.SettingsHandlers[n].TypeName);
  11154             TreePop();
  11155         }
  11156         if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
  11157         {
  11158             for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
  11159                 DebugNodeWindowSettings(settings);
  11160             TreePop();
  11161         }
  11162 
  11163         if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
  11164         {
  11165             for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
  11166                 DebugNodeTableSettings(settings);
  11167             TreePop();
  11168         }
  11169 
  11170 #ifdef IMGUI_HAS_DOCK
  11171 #endif // #ifdef IMGUI_HAS_DOCK
  11172 
  11173         if (TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size()))
  11174         {
  11175             InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, GetTextLineHeight() * 20), ImGuiInputTextFlags_ReadOnly);
  11176             TreePop();
  11177         }
  11178         TreePop();
  11179     }
  11180 
  11181     // Misc Details
  11182     if (TreeNode("Internal state"))
  11183     {
  11184         const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
  11185 
  11186         Text("WINDOWING");
  11187         Indent();
  11188         Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
  11189         Text("HoveredWindow->Root: '%s'", g.HoveredWindow ? g.HoveredWindow->RootWindow->Name : "NULL");
  11190         Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL");
  11191         Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
  11192         Unindent();
  11193 
  11194         Text("ITEMS");
  11195         Indent();
  11196         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]);
  11197         Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
  11198         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
  11199         Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
  11200         Unindent();
  11201 
  11202         Text("NAV,FOCUS");
  11203         Indent();
  11204         Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
  11205         Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
  11206         Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
  11207         Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
  11208         Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
  11209         Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
  11210         Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
  11211         Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
  11212         Unindent();
  11213 
  11214         TreePop();
  11215     }
  11216 
  11217     // Overlay: Display windows Rectangles and Begin Order
  11218     if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder)
  11219     {
  11220         for (int n = 0; n < g.Windows.Size; n++)
  11221         {
  11222             ImGuiWindow* window = g.Windows[n];
  11223             if (!window->WasActive)
  11224                 continue;
  11225             ImDrawList* draw_list = GetForegroundDrawList(window);
  11226             if (cfg->ShowWindowsRects)
  11227             {
  11228                 ImRect r = Funcs::GetWindowRect(window, cfg->ShowWindowsRectsType);
  11229                 draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
  11230             }
  11231             if (cfg->ShowWindowsBeginOrder && !(window->Flags & ImGuiWindowFlags_ChildWindow))
  11232             {
  11233                 char buf[32];
  11234                 ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
  11235                 float font_size = GetFontSize();
  11236                 draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
  11237                 draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf);
  11238             }
  11239         }
  11240     }
  11241 
  11242     // Overlay: Display Tables Rectangles
  11243     if (cfg->ShowTablesRects)
  11244     {
  11245         for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
  11246         {
  11247             ImGuiTable* table = g.Tables.GetByIndex(table_n);
  11248             if (table->LastFrameActive < g.FrameCount - 1)
  11249                 continue;
  11250             ImDrawList* draw_list = GetForegroundDrawList(table->OuterWindow);
  11251             if (cfg->ShowTablesRectsType >= TRT_ColumnsRect)
  11252             {
  11253                 for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
  11254                 {
  11255                     ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, column_n);
  11256                     ImU32 col = (table->HoveredColumnBody == column_n) ? IM_COL32(255, 255, 128, 255) : IM_COL32(255, 0, 128, 255);
  11257                     float thickness = (table->HoveredColumnBody == column_n) ? 3.0f : 1.0f;
  11258                     draw_list->AddRect(r.Min, r.Max, col, 0.0f, 0, thickness);
  11259                 }
  11260             }
  11261             else
  11262             {
  11263                 ImRect r = Funcs::GetTableRect(table, cfg->ShowTablesRectsType, -1);
  11264                 draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
  11265             }
  11266         }
  11267     }
  11268 
  11269 #ifdef IMGUI_HAS_DOCK
  11270     // Overlay: Display Docking info
  11271     if (show_docking_nodes && g.IO.KeyCtrl)
  11272     {
  11273     }
  11274 #endif // #ifdef IMGUI_HAS_DOCK
  11275 
  11276     End();
  11277 }
  11278 
  11279 // [DEBUG] Display contents of Columns
  11280 void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
  11281 {
  11282     if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
  11283         return;
  11284     BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
  11285     for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
  11286         BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
  11287     TreePop();
  11288 }
  11289 
  11290 // [DEBUG] Display contents of ImDrawList
  11291 void ImGui::DebugNodeDrawList(ImGuiWindow* window, const ImDrawList* draw_list, const char* label)
  11292 {
  11293     ImGuiContext& g = *GImGui;
  11294     ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
  11295     int cmd_count = draw_list->CmdBuffer.Size;
  11296     if (cmd_count > 0 && draw_list->CmdBuffer.back().ElemCount == 0 && draw_list->CmdBuffer.back().UserCallback == NULL)
  11297         cmd_count--;
  11298     bool node_open = 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, cmd_count);
  11299     if (draw_list == GetWindowDrawList())
  11300     {
  11301         SameLine();
  11302         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)
  11303         if (node_open)
  11304             TreePop();
  11305         return;
  11306     }
  11307 
  11308     ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
  11309     if (window && IsItemHovered())
  11310         fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
  11311     if (!node_open)
  11312         return;
  11313 
  11314     if (window && !window->WasActive)
  11315         TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!");
  11316 
  11317     for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.Data; pcmd < draw_list->CmdBuffer.Data + cmd_count; pcmd++)
  11318     {
  11319         if (pcmd->UserCallback)
  11320         {
  11321             BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
  11322             continue;
  11323         }
  11324 
  11325         char buf[300];
  11326         ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d tris, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
  11327             pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId,
  11328             pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
  11329         bool pcmd_node_open = TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
  11330         if (IsItemHovered() && (cfg->ShowDrawCmdMesh || cfg->ShowDrawCmdBoundingBoxes) && fg_draw_list)
  11331             DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, cfg->ShowDrawCmdMesh, cfg->ShowDrawCmdBoundingBoxes);
  11332         if (!pcmd_node_open)
  11333             continue;
  11334 
  11335         // Calculate approximate coverage area (touched pixel count)
  11336         // This will be in pixels squared as long there's no post-scaling happening to the renderer output.
  11337         const ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
  11338         const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + pcmd->VtxOffset;
  11339         float total_area = 0.0f;
  11340         for (unsigned int idx_n = pcmd->IdxOffset; idx_n < pcmd->IdxOffset + pcmd->ElemCount; )
  11341         {
  11342             ImVec2 triangle[3];
  11343             for (int n = 0; n < 3; n++, idx_n++)
  11344                 triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos;
  11345             total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);
  11346         }
  11347 
  11348         // Display vertex information summary. Hover to get all triangles drawn in wire-frame
  11349         ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);
  11350         Selectable(buf);
  11351         if (IsItemHovered() && fg_draw_list)
  11352             DebugNodeDrawCmdShowMeshAndBoundingBox(fg_draw_list, draw_list, pcmd, true, false);
  11353 
  11354         // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
  11355         ImGuiListClipper clipper;
  11356         clipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
  11357         while (clipper.Step())
  11358             for (int prim = clipper.DisplayStart, idx_i = pcmd->IdxOffset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++)
  11359             {
  11360                 char* buf_p = buf, * buf_end = buf + IM_ARRAYSIZE(buf);
  11361                 ImVec2 triangle[3];
  11362                 for (int n = 0; n < 3; n++, idx_i++)
  11363                 {
  11364                     const ImDrawVert& v = vtx_buffer[idx_buffer ? idx_buffer[idx_i] : idx_i];
  11365                     triangle[n] = v.pos;
  11366                     buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
  11367                         (n == 0) ? "Vert:" : "     ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
  11368                 }
  11369 
  11370                 Selectable(buf, false);
  11371                 if (fg_draw_list && IsItemHovered())
  11372                 {
  11373                     ImDrawListFlags backup_flags = fg_draw_list->Flags;
  11374                     fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
  11375                     fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f);
  11376                     fg_draw_list->Flags = backup_flags;
  11377                 }
  11378             }
  11379         TreePop();
  11380     }
  11381     TreePop();
  11382 }
  11383 
  11384 // [DEBUG] Display mesh/aabb of a ImDrawCmd
  11385 void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb)
  11386 {
  11387     IM_ASSERT(show_mesh || show_aabb);
  11388     ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
  11389     ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data + draw_cmd->VtxOffset;
  11390 
  11391     // Draw wire-frame version of all triangles
  11392     ImRect clip_rect = draw_cmd->ClipRect;
  11393     ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
  11394     ImDrawListFlags backup_flags = out_draw_list->Flags;
  11395     out_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
  11396     for (unsigned int idx_n = draw_cmd->IdxOffset; idx_n < draw_cmd->IdxOffset + draw_cmd->ElemCount; )
  11397     {
  11398         ImVec2 triangle[3];
  11399         for (int n = 0; n < 3; n++, idx_n++)
  11400             vtxs_rect.Add((triangle[n] = vtx_buffer[idx_buffer ? idx_buffer[idx_n] : idx_n].pos));
  11401         if (show_mesh)
  11402             out_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), ImDrawFlags_Closed, 1.0f); // In yellow: mesh triangles
  11403     }
  11404     // Draw bounding boxes
  11405     if (show_aabb)
  11406     {
  11407         out_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU
  11408         out_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles
  11409     }
  11410     out_draw_list->Flags = backup_flags;
  11411 }
  11412 
  11413 // [DEBUG] Display contents of ImGuiStorage
  11414 void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
  11415 {
  11416     if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
  11417         return;
  11418     for (int n = 0; n < storage->Data.Size; n++)
  11419     {
  11420         const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
  11421         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.
  11422     }
  11423     TreePop();
  11424 }
  11425 
  11426 // [DEBUG] Display contents of ImGuiTabBar
  11427 void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
  11428 {
  11429     // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.
  11430     char buf[256];
  11431     char* p = buf;
  11432     const char* buf_end = buf + IM_ARRAYSIZE(buf);
  11433     const bool is_active = (tab_bar->PrevFrameVisible >= GetFrameCount() - 2);
  11434     p += ImFormatString(p, buf_end - p, "%s 0x%08X (%d tabs)%s", label, tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
  11435     IM_UNUSED(p);
  11436     if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
  11437     bool open = TreeNode(tab_bar, "%s", buf);
  11438     if (!is_active) { PopStyleColor(); }
  11439     if (is_active && IsItemHovered())
  11440     {
  11441         ImDrawList* draw_list = GetForegroundDrawList();
  11442         draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));
  11443         draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMinX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
  11444         draw_list->AddLine(ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Min.y), ImVec2(tab_bar->ScrollingRectMaxX, tab_bar->BarRect.Max.y), IM_COL32(0, 255, 0, 255));
  11445     }
  11446     if (open)
  11447     {
  11448         for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
  11449         {
  11450             const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
  11451             PushID(tab);
  11452             if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2);
  11453             if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine();
  11454             Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f",
  11455                 tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "", tab->Offset, tab->Width, tab->ContentWidth);
  11456             PopID();
  11457         }
  11458         TreePop();
  11459     }
  11460 }
  11461 
  11462 void ImGui::DebugNodeViewport(ImGuiViewportP* viewport)
  11463 {
  11464     SetNextItemOpen(true, ImGuiCond_Once);
  11465     if (TreeNode("viewport0", "Viewport #%d", 0))
  11466     {
  11467         ImGuiWindowFlags flags = viewport->Flags;
  11468         BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f",
  11469             viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y,
  11470             viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y);
  11471         BulletText("Flags: 0x%04X =%s%s%s", viewport->Flags,
  11472             (flags & ImGuiViewportFlags_IsPlatformWindow)  ? " IsPlatformWindow"  : "",
  11473             (flags & ImGuiViewportFlags_IsPlatformMonitor) ? " IsPlatformMonitor" : "",
  11474             (flags & ImGuiViewportFlags_OwnedByApp)        ? " OwnedByApp"        : "");
  11475         for (int layer_i = 0; layer_i < IM_ARRAYSIZE(viewport->DrawDataBuilder.Layers); layer_i++)
  11476             for (int draw_list_i = 0; draw_list_i < viewport->DrawDataBuilder.Layers[layer_i].Size; draw_list_i++)
  11477                 DebugNodeDrawList(NULL, viewport->DrawDataBuilder.Layers[layer_i][draw_list_i], "DrawList");
  11478         TreePop();
  11479     }
  11480 }
  11481 
  11482 void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
  11483 {
  11484     if (window == NULL)
  11485     {
  11486         BulletText("%s: NULL", label);
  11487         return;
  11488     }
  11489 
  11490     ImGuiContext& g = *GImGui;
  11491     const bool is_active = window->WasActive;
  11492     ImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None;
  11493     if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
  11494     const bool open = TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*");
  11495     if (!is_active) { PopStyleColor(); }
  11496     if (IsItemHovered() && is_active)
  11497         GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
  11498     if (!open)
  11499         return;
  11500 
  11501     if (window->MemoryCompacted)
  11502         TextDisabled("Note: some memory buffers have been compacted/freed.");
  11503 
  11504     ImGuiWindowFlags flags = window->Flags;
  11505     DebugNodeDrawList(window, window->DrawList, "DrawList");
  11506     BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f) Ideal (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y, window->ContentSizeIdeal.x, window->ContentSizeIdeal.y);
  11507     BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
  11508         (flags & ImGuiWindowFlags_ChildWindow)  ? "Child " : "",      (flags & ImGuiWindowFlags_Tooltip)     ? "Tooltip "   : "",  (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
  11509         (flags & ImGuiWindowFlags_Modal)        ? "Modal " : "",      (flags & ImGuiWindowFlags_ChildMenu)   ? "ChildMenu " : "",  (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
  11510         (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
  11511     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" : "");
  11512     BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
  11513     BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
  11514     for (int layer = 0; layer < ImGuiNavLayer_COUNT; layer++)
  11515     {
  11516         ImRect r = window->NavRectRel[layer];
  11517         if (r.Min.x >= r.Max.y && r.Min.y >= r.Max.y)
  11518         {
  11519             BulletText("NavLastIds[%d]: 0x%08X", layer, window->NavLastIds[layer]);
  11520             continue;
  11521         }
  11522         BulletText("NavLastIds[%d]: 0x%08X at +(%.1f,%.1f)(%.1f,%.1f)", layer, window->NavLastIds[layer], r.Min.x, r.Min.y, r.Max.x, r.Max.y);
  11523         if (IsItemHovered())
  11524             GetForegroundDrawList(window)->AddRect(r.Min + window->Pos, r.Max + window->Pos, IM_COL32(255, 255, 0, 255));
  11525     }
  11526     BulletText("NavLayersActiveMask: %X, NavLastChildNavWindow: %s", window->DC.NavLayersActiveMask, window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
  11527     if (window->RootWindow != window)       { DebugNodeWindow(window->RootWindow, "RootWindow"); }
  11528     if (window->ParentWindow != NULL)       { DebugNodeWindow(window->ParentWindow, "ParentWindow"); }
  11529     if (window->DC.ChildWindows.Size > 0)   { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
  11530     if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
  11531     {
  11532         for (int n = 0; n < window->ColumnsStorage.Size; n++)
  11533             DebugNodeColumns(&window->ColumnsStorage[n]);
  11534         TreePop();
  11535     }
  11536     DebugNodeStorage(&window->StateStorage, "Storage");
  11537     TreePop();
  11538 }
  11539 
  11540 void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings* settings)
  11541 {
  11542     Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
  11543         settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
  11544 }
  11545 
  11546 void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>* windows, const char* label)
  11547 {
  11548     if (!TreeNode(label, "%s (%d)", label, windows->Size))
  11549         return;
  11550     Text("(In front-to-back order:)");
  11551     for (int i = windows->Size - 1; i >= 0; i--) // Iterate front to back
  11552     {
  11553         PushID((*windows)[i]);
  11554         DebugNodeWindow((*windows)[i], "Window");
  11555         PopID();
  11556     }
  11557     TreePop();
  11558 }
  11559 
  11560 #else
  11561 
  11562 void ImGui::ShowMetricsWindow(bool*) {}
  11563 void ImGui::DebugNodeColumns(ImGuiOldColumns*) {}
  11564 void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {}
  11565 void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList*, const ImDrawList*, const ImDrawCmd*, bool, bool) {}
  11566 void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}
  11567 void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}
  11568 void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}
  11569 void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {}
  11570 void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {}
  11571 void ImGui::DebugNodeViewport(ImGuiViewportP*) {}
  11572 
  11573 #endif
  11574 
  11575 //-----------------------------------------------------------------------------
  11576 
  11577 // Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
  11578 // 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.
  11579 #ifdef IMGUI_INCLUDE_IMGUI_USER_INL
  11580 #include "imgui_user.inl"
  11581 #endif
  11582 
  11583 //-----------------------------------------------------------------------------
  11584 
  11585 #endif // #ifndef IMGUI_DISABLE