Changeset e66fd66 in opengl-game for IMGUI/imgui.cpp


Ignore:
Timestamp:
Dec 5, 2020, 7:14:31 PM (4 years ago)
Author:
Dmitry Portnoy <dportnoy@…>
Branches:
feature/imgui-sdl, master
Children:
95c657f
Parents:
78c3045
Message:

In OpenGLReference, change all enums to enum classes and update IMGUI to the latest version

File:
1 edited

Legend:

Unmodified
Added
Removed
  • IMGUI/imgui.cpp

    r78c3045 re66fd66  
    1 // dear imgui, v1.61 WIP
     1// dear imgui, v1.79
    22// (main code and documentation)
    33
    4 // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
    5 // Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
    6 // Get latest version at https://github.com/ocornut/imgui
    7 // Releases change-log at https://github.com/ocornut/imgui/releases
    8 // Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269
     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/3488 (please post your screenshots/video there!)
     15// - Glossary              https://github.com/ocornut/imgui/wiki/Glossary
     16// - Wiki                  https://github.com/ocornut/imgui/wiki
     17// - Issues & support      https://github.com/ocornut/imgui/issues
     18
    919// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
    10 // This library is free but I need your support to sustain development and maintenance.
    11 // If you work for a company, please consider financial support, see README. For individuals: https://www.patreon.com/imgui
     20// See LICENSE.txt for copyright and licensing details (standard MIT License).
     21// This library is free but needs your support to sustain development and maintenance.
     22// Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.org".
     23// Individuals: you can support continued development via donations. See docs/README or web page.
    1224
    1325// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
    14 // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without 
    15 // modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't 
    16 // come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you 
     26// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
     27// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
     28// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
    1729// to a better solution or official support for them.
    1830
    1931/*
    2032
    21 Index
     33Index of this file:
     34
     35DOCUMENTATION
     36
    2237- MISSION STATEMENT
    2338- END-USER GUIDE
    24 - PROGRAMMER GUIDE (read me!)
    25 - Read first
    26 - How to update to a newer version of Dear ImGui
    27 - Getting started with integrating Dear ImGui in your code/engine
    28 - Using gamepad/keyboard navigation controls [BETA]
     39- PROGRAMMER GUIDE
     40  - READ FIRST
     41  - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
     42  - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
     43  - HOW A SIMPLE APPLICATION MAY LOOK LIKE
     44  - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
     45  - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
    2946- API BREAKING CHANGES (read me when you update!)
    30 - ISSUES & TODO LIST
    31 - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
    32 - How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
    33 - How can I display an image? What is ImTextureID, how does it works?
    34 - How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack.
    35 - How can I load a different font than the default?
    36 - How can I easily use icons in my application?
    37 - How can I load multiple fonts?
    38 - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
    39 - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
    40 - I integrated Dear ImGui in my engine and the text or lines are blurry..
    41 - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
    42 - How can I help?
    43 - ISSUES & TODO-LIST
    44 - CODE
    45 
    46 
    47 MISSION STATEMENT
    48 =================
    49 
    50 - Easy to use to create code-driven and data-driven tools
    51 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools
    52 - Easy to hack and improve
    53 - Minimize screen real-estate usage
    54 - Minimize setup and maintenance
    55 - Minimize state storage on user side
    56 - Portable, minimize dependencies, run on target (consoles, phones, etc.)
    57 - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,
    58 opening a tree node for the first time, etc. but a typical frame should not allocate anything)
    59 
    60 Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
    61 - Doesn't look fancy, doesn't animate
    62 - Limited layout features, intricate layouts are typically crafted in code
    63 
    64 
    65 END-USER GUIDE
    66 ==============
    67 
    68 - Double-click on title bar to collapse window.
    69 - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin().
    70 - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents).
    71 - Click and drag on any empty space to move window.
    72 - TAB/SHIFT+TAB to cycle through keyboard editable fields.
    73 - CTRL+Click on a slider or drag box to input value as text.
    74 - Use mouse wheel to scroll.
    75 - Text editor:
    76 - Hold SHIFT or use mouse to select text.
    77 - CTRL+Left/Right to word jump.
    78 - CTRL+Shift+Left/Right to select words.
    79 - CTRL+A our Double-Click to select all.
    80 - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
    81 - CTRL+Z,CTRL+Y to undo/redo.
    82 - ESCAPE to revert text to its original value.
    83 - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
    84 - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
    85 - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
    86 - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW
    87 
    88 
    89 PROGRAMMER GUIDE
    90 ================
    91 
    92 READ FIRST
    93 
    94 - Read the FAQ below this section!
    95 - 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
    96 or destruction steps, less data retention on your side, less state duplication, less state synchronization, less bugs.
    97 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
    98 - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861
    99 
    100 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
    101 
    102 - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
    103 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
    104 If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
    105 from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
    106 likely be a comment about it. Please report any issue to the GitHub page!
    107 - Try to keep your copy of dear imgui reasonably up to date.
    108 
    109 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
    110 
    111 - Run and study the examples and demo to get acquainted with the library.
    112 - Add the Dear ImGui source files to your projects, using your preferred build system.
    113 It is recommended you build the .cpp files as part of your project and not as a library.
    114 - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types.
    115 - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/ folder.
    116 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
    117 
    118 - Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize
    119 (application resolution). Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic
    120 integration you don't need to worry about it all.
    121 - Init: call io.Fonts->GetTexDataAsRGBA32(...), it will build the font atlas texture, then load the texture pixels into graphics memory.
    122 - Every frame:
    123 - In your main loop as early a possible, fill the IO fields marked 'Input' (e.g. mouse position, buttons, keyboard info, etc.)
    124 - Call ImGui::NewFrame() to begin the frame
    125 - You can use any ImGui function you want between NewFrame() and Render()
    126 - Call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your io.RenderDrawListFn handler.
    127 (Even if you don't render, call Render() and ignore the callback, or call EndFrame() instead. Otherwise some features will break)
    128 - All rendering information are stored into command-lists until ImGui::Render() is called.
    129 - Dear ImGui never touches or knows about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide.
    130 - Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases
    131 of your own application.
    132 - Refer to the examples applications in the examples/ folder for instruction on how to setup your code.
    133 - A minimal application skeleton may be:
    134 
    135 // Application init
    136 ImGui::CreateContext();
    137 ImGuiIO& io = ImGui::GetIO();
    138 io.DisplaySize.x = 1920.0f;
    139 io.DisplaySize.y = 1280.0f;
    140 // TODO: Fill others settings of the io structure later.
    141 
    142 // Load texture atlas (there is a default font so you don't need to care about choosing a font yet)
    143 unsigned char* pixels;
    144 int width, height;
    145 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
    146 // TODO: At this points you've got the texture data and you need to upload that your your graphic system:
    147 MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA)
    148 // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'. This will be passed back to your via the renderer.
    149 io.Fonts->TexID = (void*)texture;
    150 
    151 // Application main loop
    152 while (true)
    153 {
    154 // Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or write to those fields from your Windows message loop handlers, etc.)
    155 ImGuiIO& io = ImGui::GetIO();
    156 io.DeltaTime = 1.0f/60.0f;
    157 io.MousePos = mouse_pos;
    158 io.MouseDown[0] = mouse_button_0;
    159 io.MouseDown[1] = mouse_button_1;
    160 
    161 // Call NewFrame(), after this point you can use ImGui::* functions anytime
    162 ImGui::NewFrame();
    163 
    164 // Most of your application code here
    165 MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
    166 MyGameRender(); // may use any ImGui functions as well!
    167 
    168 // Render & swap video buffers
    169 ImGui::Render();
    170 MyImGuiRenderFunction(ImGui::GetDrawData());
    171 SwapBuffers();
    172 }
    173 
    174 // Shutdown
    175 ImGui::DestroyContext();
    176 
    177 
    178 - A minimal render function skeleton may be:
    179 
    180 void void MyRenderFunction(ImDrawData* draw_data)
    181 {
    182 // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
    183 // TODO: Setup viewport, orthographic projection matrix
    184 // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
    185 for (int n = 0; n < draw_data->CmdListsCount; n++)
    186 {
    187 const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;  // vertex buffer generated by ImGui
    188 const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;   // index buffer generated by ImGui
    189 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
    190 {
    191 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
    192 if (pcmd->UserCallback)
    193 {
    194 pcmd->UserCallback(cmd_list, pcmd);
    195 }
    196 else
    197 {
    198 // The texture for the draw call is specified by pcmd->TextureId.
    199 // The vast majority of draw calls with use the imgui texture atlas, which value you have set yourself during initialization.
    200 MyEngineBindTexture(pcmd->TextureId);
    201 
    202 // We are using scissoring to clip some objects. All low-level graphics API supports it.
    203 // If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
    204 // (some elements visible outside their bounds) but you can fix that once everywhere else works!
    205 MyEngineScissor((int)pcmd->ClipRect.x, (int)pcmd->ClipRect.y, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
    206 
    207 // Render 'pcmd->ElemCount/3' indexed triangles.
    208 // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits if your engine doesn't support 16-bits indices.
    209 MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
    210 }
    211 idx_buffer += pcmd->ElemCount;
    212 }
    213 }
    214 }
    215 
    216 - The examples/ folders contains many functional implementation of the pseudo-code above.
    217 - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated.
    218 They tell you if ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the rest of your application.
    219 However, in both cases you need to pass on the inputs to imgui. Read the FAQ below for more information about those flags.
    220 - Please read the FAQ above. Amusingly, it is called a FAQ because people frequently have the same issues!
    221 
    222 USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS [BETA]
    223 
    224 - The gamepad/keyboard navigation is in Beta. Ask questions and report issues at https://github.com/ocornut/imgui/issues/787
    225 - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
    226 - Gamepad:
    227 - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
    228 - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame().
    229 Note that io.NavInputs[] is cleared by EndFrame().
    230 - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
    231 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
    232 - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
    233 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.).
    234 - You can download PNG/PSD files depicting the gamepad controls for common controllers at: goo.gl/9LgVZW.
    235 - 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
    236 to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
    237 - Keyboard:
    238 - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
    239 NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
    240 - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag
    241 will be set. For more advanced uses, you may want to read from:
    242 - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
    243 - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
    244 - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
    245 Please reach out if you think the game vs navigation input sharing could be improved.
    246 - Mouse:
    247 - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
    248 - 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.
    249 - 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.
    250 Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
    251 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.
    252 When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that.
    253 (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!)
    254 (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
    255 to set a boolean to ignore your other external mouse positions until the external source is moved again.)
    256 
    257 
    258 API BREAKING CHANGES
    259 ====================
    260 
    261 Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
    262 Here is a change-log of API breaking changes, if you are using one of the functions listed, expect to have to fix some code.
    263 Also read releases logs https://github.com/ocornut/imgui/releases for more details.
    264 
    265 - 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", consistent with other functions. Kept redirection functions (will obsolete).
    266 - 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.
    267 - 2018/03/20 (1.60) - Renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch).
    268 - 2018/03/12 (1.60) - Removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
    269 - 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.
    270 - 2018/03/03 (1.60) - Renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
    271 - 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.
    272 - 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.
    273 - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
    274 - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
    275 - removed Shutdown() function, as DestroyContext() serve this purpose.
    276 - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
    277 - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
    278 - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
    279 - 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.
    280 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
    281 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
    282 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
    283 - 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.
    284 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
    285 - 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
    286 - 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.
    287 - 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.
    288 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
    289 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
    290 - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
    291 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
    292 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
    293 - 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.
    294 - 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.
    295 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.
    296 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
    297 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
    298 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
    299 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
    300 - 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.
    301 - 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.
    302 - 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.
    303 removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
    304 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
    305 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
    306 - 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).
    307 - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
    308 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
    309 - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
    310 - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
    311 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
    312 - 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.
    313 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame.
    314 - 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.
    315 - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete).
    316 - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete).
    317 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
    318 - 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.
    319 - 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.
    320 - 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))'
    321 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
    322 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
    323 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
    324 - 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().
    325 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
    326 - 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.
    327 - 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.
    328 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
    329 If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
    330 However if your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
    331 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.
    332 ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col)
    333 {
    334 float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a;
    335 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);
    336 }
    337 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.
    338 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
    339 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
    340 - 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).
    341 - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDraw::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.
    342 - 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).
    343 - 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)
    344 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
    345 - 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.
    346 - 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.
    347 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
    348 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
    349 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
    350 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.
    351 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!
    352 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
    353 - 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.
    354 - 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
    355 - 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.
    356 you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
    357 - 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.
    358 this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
    359 - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
    360 - the signature of the io.RenderDrawListsFn handler has changed!
    361 old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
    362 new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
    363 argument:   'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
    364 ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
    365 ImDrawCmd:  'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
    366 - 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.
    367 - 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!
    368 - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
    369 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
    370 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
    371 - 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.
    372 - 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
    373 - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry!
    374 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
    375 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
    376 - 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.
    377 - 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.
    378 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
    379 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
    380 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
    381 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
    382 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
    383 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
    384 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
    385 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
    386 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
    387 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
    388 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
    389 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
    390 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
    391 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
    392 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
    393 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
    394 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
    395 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
    396 font init:  const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>
    397 became:     unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier;
    398 you now more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
    399 it is now recommended that you sample the font texture with bilinear interpolation.
    400 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
    401 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
    402 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
    403 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
    404 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
    405 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
    406 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
    407 - 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)
    408 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
    409 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
    410 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
    411 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
    412 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
    413 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
    414 
    415 
    416 ISSUES & TODO-LIST
    417 ==================
    418 See TODO.txt
    419 
    420 
    421 FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
    422 ======================================
    423 
    424 Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
    425 A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure.
    426 - When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
    427 - When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application.
    428 - When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS).
    429 Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false.
    430 This is because imgui needs to detect that you clicked in the void to unfocus its windows.
    431 Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!).
    432 It handle mouse dragging correctly (both dragging that started over your application or over an imgui window) and handle e.g. modal windows blocking inputs.
    433 Those flags are updated by ImGui::NewFrame(). Preferably read the flags after calling NewFrame() if you can afford it, but reading them before is also
    434 perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to NewFrameUpdateHoveredWindowAndCaptureFlags().
    435 Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically
    436 have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs
    437 were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.)
    438 
    439 Q: How can I display an image? What is ImTextureID, how does it works?
    440 A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function.
    441 Dear ImGui knows nothing about what those bits represent, it just passes them around. It is up to you to decide what you want the void* to carry!
    442 It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc.
    443 At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render.
    444 Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing.
    445 (C++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!)
    446 To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions.
    447 Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use.
    448 You may call ImGui::ShowMetricsWindow() to explore active draw lists and visualize/understand how the draw data is generated.
    449 It is your responsibility to get textures uploaded to your GPU.
    450 
    451 Q: How can I have multiple widgets with the same label or without a label?
    452 A: A primer on labels and the ID Stack...
    453 
    454 - Elements that are typically not clickable, such as Text() items don't need an ID.
    455 
    456 - Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui
    457 often needs to remember what is the "active" widget). To do so they need a unique ID. Unique ID
    458 are typically derived from a string label, an integer index or a pointer.
    459 
    460 Button("OK");          // Label = "OK",     ID = top of id stack + hash of "OK"
    461 Button("Cancel");      // Label = "Cancel", ID = top of id stack + hash of "Cancel"
    462 
    463 - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having
    464 two buttons labeled "OK" in different windows or different tree locations is fine.
    465 
    466 - If you have a same ID twice in the same location, you'll have a conflict:
    467 
    468 Button("OK");
    469 Button("OK");          // ID collision! Interacting with either button will trigger the first one.
    470 
    471 Fear not! this is easy to solve and there are many ways to solve it!
    472 
    473 - Solving ID conflict in a simple/local context:
    474 When passing a label you can optionally specify extra ID information within string itself.
    475 Use "##" to pass a complement to the ID that won't be visible to the end-user.
    476 This helps solving the simple collision cases when you know e.g. at compilation time which items
    477 are going to be created:
    478 
    479 Button("Play");        // Label = "Play",   ID = top of id stack + hash of "Play"
    480 Button("Play##foo1");  // Label = "Play",   ID = top of id stack + hash of "Play##foo1" (different from above)
    481 Button("Play##foo2");  // Label = "Play",   ID = top of id stack + hash of "Play##foo2" (different from above)
    482 
    483 - If you want to completely hide the label, but still need an ID:
    484 
    485 Checkbox("##On", &b);  // Label = "",       ID = top of id stack + hash of "##On" (no label!)
    486 
    487 - Occasionally/rarely you might want change a label while preserving a constant ID. This allows
    488 you to animate labels. For example you may want to include varying information in a window title bar,
    489 but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID:
    490 
    491 Button("Hello###ID";   // Label = "Hello",  ID = top of id stack + hash of "ID"
    492 Button("World###ID";   // Label = "World",  ID = top of id stack + hash of "ID" (same as above)
    493 
    494 sprintf(buf, "My game (%f FPS)###MyGame", fps);
    495 Begin(buf);            // Variable label,   ID = hash of "MyGame"
    496 
    497 - Solving ID conflict in a more general manner:
    498 Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts
    499 within the same window. This is the most convenient way of distinguishing ID when iterating and
    500 creating many UI elements programmatically.
    501 You can push a pointer, a string or an integer value into the ID stack.
    502 Remember that ID are formed from the concatenation of _everything_ in the ID stack!
    503 
    504 for (int i = 0; i < 100; i++)
    505 {
    506 PushID(i);
    507 Button("Click");   // Label = "Click",  ID = top of id stack + hash of integer + hash of "Click"
    508 PopID();
    509 }
    510 
    511 for (int i = 0; i < 100; i++)
    512 {
    513 MyObject* obj = Objects[i];
    514 PushID(obj);
    515 Button("Click");   // Label = "Click",  ID = top of id stack + hash of pointer + hash of "Click"
    516 PopID();
    517 }
    518 
    519 for (int i = 0; i < 100; i++)
    520 {
    521 MyObject* obj = Objects[i];
    522 PushID(obj->Name);
    523 Button("Click");   // Label = "Click",  ID = top of id stack + hash of string + hash of "Click"
    524 PopID();
    525 }
    526 
    527 - More example showing that you can stack multiple prefixes into the ID stack:
    528 
    529 Button("Click");     // Label = "Click",  ID = top of id stack + hash of "Click"
    530 PushID("node");
    531 Button("Click");     // Label = "Click",  ID = top of id stack + hash of "node" + hash of "Click"
    532 PushID(my_ptr);
    533 Button("Click"); // Label = "Click",  ID = top of id stack + hash of "node" + hash of ptr + hash of "Click"
    534 PopID();
    535 PopID();
    536 
    537 - Tree nodes implicitly creates a scope for you by calling PushID().
    538 
    539 Button("Click");     // Label = "Click",  ID = top of id stack + hash of "Click"
    540 if (TreeNode("node"))
    541 {
    542 Button("Click");   // Label = "Click",  ID = top of id stack + hash of "node" + hash of "Click"
    543 TreePop();
    544 }
    545 
    546 - When working with trees, ID are used to preserve the open/close state of each tree node.
    547 Depending on your use cases you may want to use strings, indices or pointers as ID.
    548 e.g. when following a single pointer that may change over time, using a static string as ID
    549 will preserve your node open/closed state when the targeted object change.
    550 e.g. when displaying a list of objects, using indices or pointers as ID will preserve the
    551 node open/closed state differently. See what makes more sense in your situation!
    552 
    553 Q: How can I load a different font than the default?
    554 A: Use the font atlas to load the TTF/OTF file you want:
    555 ImGuiIO& io = ImGui::GetIO();
    556 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
    557 io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
    558 (default is ProggyClean.ttf, rendered at size 13, embedded in dear imgui's source code)
    559 
    560 New programmers: remember that in C/C++ and most programming languages if you want to use a
    561 backslash \ within a string literal, you need to write it double backslash "\\":
    562 io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels);   // WRONG (you are escape the M here!)
    563 io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels);  // CORRECT
    564 io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels);   // ALSO CORRECT
    565 
    566 Q: How can I easily use icons in my application?
    567 A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you
    568 main font. Then you can refer to icons within your strings. Read 'How can I load multiple fonts?'
    569 and the file 'misc/fonts/README.txt' for instructions and useful header files.
    570 
    571 Q: How can I load multiple fonts?
    572 A: Use the font atlas to pack them into a single texture:
    573 (Read misc/fonts/README.txt and the code in ImFontAtlas for more details.)
    574 
    575 ImGuiIO& io = ImGui::GetIO();
    576 ImFont* font0 = io.Fonts->AddFontDefault();
    577 ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
    578 ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
    579 io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
    580 // the first loaded font gets used by default
    581 // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
    582 
    583 // Options
    584 ImFontConfig config;
    585 config.OversampleH = 3;
    586 config.OversampleV = 1;
    587 config.GlyphOffset.y -= 2.0f;      // Move everything by 2 pixels up
    588 config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters
    589 io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config);
    590 
    591 // Combine multiple fonts into one (e.g. for icon fonts)
    592 ImWchar ranges[] = { 0xf000, 0xf3ff, 0 };
    593 ImFontConfig config;
    594 config.MergeMode = true;
    595 io.Fonts->AddFontDefault();
    596 io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font
    597 io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs
    598 
    599 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
    600 A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
    601 
    602 // Add default Japanese ranges
    603 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
    604 
    605 // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need)
    606 ImVector<ImWchar> ranges;
    607 ImFontAtlas::GlyphRangesBuilder builder;
    608 builder.AddText("Hello world");                        // Add a string (here "Hello world" contains 7 unique characters)
    609 builder.AddChar(0x7262);                               // Add a specific character
    610 builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
    611 builder.BuildRanges(&ranges);                          // Build the final result (ordered ranges with all the unique characters submitted)
    612 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
    613 
    614 All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8
    615 by using the u8"hello" syntax. Specifying literal in your source code using a local code page
    616 (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
    617 Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
    618 
    619 Text input: it is up to your application to pass the right character code by calling
    620 io.AddInputCharacter(). The applications in examples/ are doing that. For languages relying
    621 on an Input Method Editor (IME), on Windows you can copy the Hwnd of your application in the
    622 io.ImeWindowHandle field. The default implementation of io.ImeSetInputScreenPosFn() will set
    623 your Microsoft IME position correctly.
    624 
    625 Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
    626 A: - You can create a dummy window. Call SetNextWindowBgAlpha(0.0f), call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flags.
    627 Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
    628 - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows.
    629 - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData.
    630 
    631 Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
    632 A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
    633 Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
    634 
    635 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
    636 A: You are probably mishandling the clipping rectangles in your render function.
    637 Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
    638 
    639 Q: How can I help?
    640 A: - If you are experienced with Dear ImGui and C++, look at the github issues, or TODO.txt and see how you want/can help!
    641 - Convince your company to fund development time! Individual users: you can also become a Patron (patreon.com/imgui) or donate on PayPal! See README.
    642 - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
    643 You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1269). Visuals are ideal as they inspire other programmers.
    644 But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
    645 - 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).
    646 
    647 - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window.
    648 this is also useful to set yourself in the context of another window (to get/set other settings)
    649 - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug".
    650 - tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle
    651 of a deep nested inner loop in your code.
    652 - tip: you can call Render() multiple times (e.g for VR renders).
    653 - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui!
     47- FREQUENTLY ASKED QUESTIONS (FAQ)
     48  - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer)
     49
     50CODE
     51(search for "[SECTION]" in the code to find them)
     52
     53// [SECTION] INCLUDES
     54// [SECTION] FORWARD DECLARATIONS
     55// [SECTION] CONTEXT AND MEMORY ALLOCATORS
     56// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
     57// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
     58// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
     59// [SECTION] MISC HELPERS/UTILITIES (File functions)
     60// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
     61// [SECTION] MISC HELPERS/UTILITIES (Color functions)
     62// [SECTION] ImGuiStorage
     63// [SECTION] ImGuiTextFilter
     64// [SECTION] ImGuiTextBuffer
     65// [SECTION] ImGuiListClipper
     66// [SECTION] STYLING
     67// [SECTION] RENDER HELPERS
     68// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
     69// [SECTION] ERROR CHECKING
     70// [SECTION] LAYOUT
     71// [SECTION] SCROLLING
     72// [SECTION] TOOLTIPS
     73// [SECTION] POPUPS
     74// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
     75// [SECTION] DRAG AND DROP
     76// [SECTION] LOGGING/CAPTURING
     77// [SECTION] SETTINGS
     78// [SECTION] PLATFORM DEPENDENT HELPERS
     79// [SECTION] METRICS/DEBUG WINDOW
    65480
    65581*/
     82
     83//-----------------------------------------------------------------------------
     84// DOCUMENTATION
     85//-----------------------------------------------------------------------------
     86
     87/*
     88
     89 MISSION STATEMENT
     90 =================
     91
     92 - Easy to use to create code-driven and data-driven tools.
     93 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
     94 - Easy to hack and improve.
     95 - Minimize setup and maintenance.
     96 - Minimize state storage on user side.
     97 - Portable, minimize dependencies, run on target (consoles, phones, etc.).
     98 - Efficient runtime and memory consumption.
     99
     100 Designed for developers and content-creators, not the typical end-user! Some of the current weaknesses includes:
     101
     102 - Doesn't look fancy, doesn't animate.
     103 - Limited layout features, intricate layouts are typically crafted in code.
     104
     105
     106 END-USER GUIDE
     107 ==============
     108
     109 - Double-click on title bar to collapse window.
     110 - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin().
     111 - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents).
     112 - Click and drag on any empty space to move window.
     113 - TAB/SHIFT+TAB to cycle through keyboard editable fields.
     114 - CTRL+Click on a slider or drag box to input value as text.
     115 - Use mouse wheel to scroll.
     116 - Text editor:
     117   - Hold SHIFT or use mouse to select text.
     118   - CTRL+Left/Right to word jump.
     119   - CTRL+Shift+Left/Right to select words.
     120   - CTRL+A our Double-Click to select all.
     121   - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
     122   - CTRL+Z,CTRL+Y to undo/redo.
     123   - ESCAPE to revert text to its original value.
     124   - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
     125   - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
     126 - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
     127 - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW
     128
     129
     130 PROGRAMMER GUIDE
     131 ================
     132
     133 READ FIRST
     134 ----------
     135 - Remember to read the FAQ (https://www.dearimgui.org/faq)
     136 - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction
     137   or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs.
     138 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
     139 - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
     140 - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
     141   You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in the FAQ.
     142 - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
     143   For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI,
     144   where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
     145 - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
     146 - This codebase is also optimized to yield decent performances with typical "Debug" builds settings.
     147 - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
     148   If you get an assert, read the messages and comments around the assert.
     149 - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace.
     150 - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.
     151   See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that.
     152   However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase.
     153 - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!).
     154
     155
     156 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
     157 ----------------------------------------------
     158 - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
     159 - Or maintain your own branch where you have imconfig.h modified.
     160 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
     161   If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
     162   from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
     163   likely be a comment about it. Please report any issue to the GitHub page!
     164 - Try to keep your copy of dear imgui reasonably up to date.
     165
     166
     167 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
     168 ---------------------------------------------------------------
     169 - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
     170 - In the majority of cases you should be able to use unmodified back-ends files available in the examples/ folder.
     171 - Add the Dear ImGui source files + selected back-end source files to your projects or using your preferred build system.
     172   It is recommended you build and statically link the .cpp files as part of your project and NOT as shared library (DLL).
     173 - 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.
     174 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
     175 - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
     176   Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
     177   phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render().
     178 - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code.
     179 - 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.
     180
     181
     182 HOW A SIMPLE APPLICATION MAY LOOK LIKE
     183 --------------------------------------
     184 EXHIBIT 1: USING THE EXAMPLE BINDINGS (= imgui_impl_XXX.cpp files from the examples/ folder).
     185 The sub-folders in examples/ contains examples applications following this structure.
     186
     187     // Application init: create a dear imgui context, setup some options, load fonts
     188     ImGui::CreateContext();
     189     ImGuiIO& io = ImGui::GetIO();
     190     // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
     191     // TODO: Fill optional fields of the io structure later.
     192     // TODO: Load TTF/OTF fonts if you don't want to use the default font.
     193
     194     // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp)
     195     ImGui_ImplWin32_Init(hwnd);
     196     ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
     197
     198     // Application main loop
     199     while (true)
     200     {
     201         // Feed inputs to dear imgui, start new frame
     202         ImGui_ImplDX11_NewFrame();
     203         ImGui_ImplWin32_NewFrame();
     204         ImGui::NewFrame();
     205
     206         // Any application code here
     207         ImGui::Text("Hello, world!");
     208
     209         // Render dear imgui into screen
     210         ImGui::Render();
     211         ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
     212         g_pSwapChain->Present(1, 0);
     213     }
     214
     215     // Shutdown
     216     ImGui_ImplDX11_Shutdown();
     217     ImGui_ImplWin32_Shutdown();
     218     ImGui::DestroyContext();
     219
     220 EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE
     221
     222     // Application init: create a dear imgui context, setup some options, load fonts
     223     ImGui::CreateContext();
     224     ImGuiIO& io = ImGui::GetIO();
     225     // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
     226     // TODO: Fill optional fields of the io structure later.
     227     // TODO: Load TTF/OTF fonts if you don't want to use the default font.
     228
     229     // Build and load the texture atlas into a texture
     230     // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)
     231     int width, height;
     232     unsigned char* pixels = NULL;
     233     io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
     234
     235     // At this point you've got the texture data and you need to upload that your your graphic system:
     236     // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.
     237     // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID.
     238     MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
     239     io.Fonts->TexID = (void*)texture;
     240
     241     // Application main loop
     242     while (true)
     243     {
     244        // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
     245        // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings)
     246        io.DeltaTime = 1.0f/60.0f;              // set the time elapsed since the previous frame (in seconds)
     247        io.DisplaySize.x = 1920.0f;             // set the current display width
     248        io.DisplaySize.y = 1280.0f;             // set the current display height here
     249        io.MousePos = my_mouse_pos;             // set the mouse position
     250        io.MouseDown[0] = my_mouse_buttons[0];  // set the mouse button states
     251        io.MouseDown[1] = my_mouse_buttons[1];
     252
     253        // Call NewFrame(), after this point you can use ImGui::* functions anytime
     254        // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere)
     255        ImGui::NewFrame();
     256
     257        // Most of your application code here
     258        ImGui::Text("Hello, world!");
     259        MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
     260        MyGameRender(); // may use any Dear ImGui functions as well!
     261
     262        // Render dear imgui, swap buffers
     263        // (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)
     264        ImGui::EndFrame();
     265        ImGui::Render();
     266        ImDrawData* draw_data = ImGui::GetDrawData();
     267        MyImGuiRenderFunction(draw_data);
     268        SwapBuffers();
     269     }
     270
     271     // Shutdown
     272     ImGui::DestroyContext();
     273
     274 To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest your application,
     275 you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
     276 Please read the FAQ and example applications for details about this!
     277
     278
     279 HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
     280 ---------------------------------------------
     281 The bindings in impl_impl_XXX.cpp files contains many working implementations of a rendering function.
     282
     283    void void MyImGuiRenderFunction(ImDrawData* draw_data)
     284    {
     285       // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
     286       // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
     287       // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
     288       // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
     289       for (int n = 0; n < draw_data->CmdListsCount; n++)
     290       {
     291          const ImDrawList* cmd_list = draw_data->CmdLists[n];
     292          const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;  // vertex buffer generated by Dear ImGui
     293          const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;   // index buffer generated by Dear ImGui
     294          for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
     295          {
     296             const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
     297             if (pcmd->UserCallback)
     298             {
     299                 pcmd->UserCallback(cmd_list, pcmd);
     300             }
     301             else
     302             {
     303                 // The texture for the draw call is specified by pcmd->TextureId.
     304                 // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.
     305                 MyEngineBindTexture((MyTexture*)pcmd->TextureId);
     306
     307                 // We are using scissoring to clip some objects. All low-level graphics API should supports it.
     308                 // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
     309                 //   (some elements visible outside their bounds) but you can fix that once everything else works!
     310                 // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize)
     311                 //   In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize.
     312                 //   However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github),
     313                 //   always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.
     314                 // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)
     315                 ImVec2 pos = draw_data->DisplayPos;
     316                 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));
     317
     318                 // Render 'pcmd->ElemCount/3' indexed triangles.
     319                 // 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.
     320                 MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
     321             }
     322             idx_buffer += pcmd->ElemCount;
     323          }
     324       }
     325    }
     326
     327
     328 USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
     329 ------------------------------------------
     330 - The gamepad/keyboard navigation is fairly functional and keeps being improved.
     331 - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse!
     332 - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787
     333 - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
     334 - Keyboard:
     335    - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
     336      NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
     337    - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag
     338      will be set. For more advanced uses, you may want to read from:
     339       - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
     340       - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
     341       - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
     342      Please reach out if you think the game vs navigation input sharing could be improved.
     343 - Gamepad:
     344    - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
     345    - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame().
     346      Note that io.NavInputs[] is cleared by EndFrame().
     347    - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
     348         0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
     349    - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
     350      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.).
     351    - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW.
     352    - 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
     353      to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
     354 - Mouse:
     355    - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
     356    - 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.
     357    - 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.
     358      Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
     359      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.
     360      When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that.
     361      (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!)
     362      (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
     363       to set a boolean to ignore your other external mouse positions until the external source is moved again.)
     364
     365
     366 API BREAKING CHANGES
     367 ====================
     368
     369 Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
     370 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.
     371 When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
     372 You can read releases logs https://github.com/ocornut/imgui/releases for more details.
     373
     374 - 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).
     375 - 2020/09/25 (1.79) - renamed ImGuiSliderFlags_ClampOnInput to ImGuiSliderFlags_AlwaysClamp. Kept redirection enum (will obsolete sooner because previous name was added recently).
     376 - 2020/09/25 (1.79) - renamed style.TabMinWidthForUnselectedCloseButton to style.TabMinWidthForCloseButton.
     377 - 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.
     378 - 2020/09/21 (1.79) - removed return value from OpenPopupOnItemClick() - returned true on mouse release on 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.
     379 - 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!
     380 - 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().
     381                       replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
     382                       worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:
     383                       - if you omitted the 'power' parameter (likely!), you are not affected.
     384                       - 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.
     385                       - 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.
     386                       see https://github.com/ocornut/imgui/issues/3361 for all details.
     387                       kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used.
     388                       for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
     389                     - 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.
     390 - 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.
     391 - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete). [NOTE: THIS WAS REVERTED IN 1.79]
     392 - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.
     393 - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular().
     394 - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.
     395 - 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.
     396 - 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.
     397 - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017):
     398                       - ShowTestWindow()                    -> use ShowDemoWindow()
     399                       - IsRootWindowFocused()               -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)
     400                       - IsRootWindowOrAnyChildFocused()     -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
     401                       - SetNextWindowContentWidth(w)        -> use SetNextWindowContentSize(ImVec2(w, 0.0f)
     402                       - GetItemsLineHeightWithSpacing()     -> use GetFrameHeightWithSpacing()
     403                       - ImGuiCol_ChildWindowBg              -> use ImGuiCol_ChildBg
     404                       - ImGuiStyleVar_ChildWindowRounding   -> use ImGuiStyleVar_ChildRounding
     405                       - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap
     406                       - IMGUI_DISABLE_TEST_WINDOWS          -> use IMGUI_DISABLE_DEMO_WINDOWS
     407 - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was the vaguely documented and rarely if ever used). Instead we added an explicit PrimUnreserve() API.
     408 - 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).
     409 - 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.
     410 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
     411 - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.
     412 - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017):
     413                       - Begin() [old 5 args version]        -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed
     414                       - IsRootWindowOrAnyChildHovered()     -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows)
     415                       - AlignFirstTextHeightToWidgets()     -> use AlignTextToFramePadding()
     416                       - SetNextWindowPosCenter()            -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f)
     417                       - ImFont::Glyph                       -> use ImFontGlyph
     418 - 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.
     419                       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.
     420                       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).
     421                       If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.
     422 - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
     423 - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
     424 - 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.
     425 - 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
     426                       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.
     427                       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.
     428                       Please reach out if you are affected.
     429 - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
     430 - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
     431 - 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.
     432 - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
     433 - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
     434 - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).
     435 - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with an arbitrary small value!
     436 - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
     437 - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
     438 - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
     439 - 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.
     440 - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
     441 - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
     442 - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
     443 - 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.
     444                       If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
     445 - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
     446 - 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.
     447                       NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.
     448                       Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.
     449 - 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).
     450 - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
     451 - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
     452 - 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.
     453 - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
     454 - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
     455 - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
     456 - 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.).
     457                       old bindings will still work as is, however prefer using the separated bindings as they will be updated to support multi-viewports.
     458                       when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call.
     459                       in particular, note that old bindings called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function.
     460 - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
     461 - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
     462 - 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.
     463                       If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
     464                       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.
     465                       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.
     466 - 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",
     467                       consistent with other functions. Kept redirection functions (will obsolete).
     468 - 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.
     469 - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch).
     470 - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
     471 - 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.
     472 - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
     473 - 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.
     474 - 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.
     475 - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
     476                       - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
     477                       - removed Shutdown() function, as DestroyContext() serve this purpose.
     478                       - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
     479                       - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
     480                       - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
     481 - 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.
     482 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
     483 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
     484 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
     485 - 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.
     486 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
     487 - 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
     488 - 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.
     489 - 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.
     490 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
     491 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
     492                     - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
     493 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
     494 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
     495 - 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.
     496 - 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.
     497                       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.
     498 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
     499 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
     500 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
     501 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
     502 - 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.
     503 - 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.
     504 - 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.
     505                       removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
     506                         IsItemHoveredRect()        --> IsItemHovered(ImGuiHoveredFlags_RectOnly)
     507                         IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
     508                         IsMouseHoveringWindow()    --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]
     509 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
     510 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
     511 - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).
     512 - 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).
     513 - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
     514 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
     515                     - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
     516                     - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
     517 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
     518 - 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.
     519 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.
     520 - 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.
     521 - 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).
     522 - 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).
     523 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
     524 - 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.
     525                     - 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.
     526                     - 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))'
     527 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
     528 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
     529 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
     530 - 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().
     531 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
     532 - 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.
     533 - 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.
     534 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
     535                       If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
     536                       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:
     537                       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); }
     538                       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.
     539 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
     540 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
     541 - 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).
     542 - 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.
     543 - 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).
     544 - 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)
     545 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
     546 - 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.
     547 - 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.
     548 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
     549 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
     550 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
     551                       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.
     552                       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!
     553 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
     554 - 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.
     555 - 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
     556 - 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.
     557                       you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
     558 - 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.
     559                       this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
     560                     - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
     561                     - the signature of the io.RenderDrawListsFn handler has changed!
     562                       old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
     563                       new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
     564                         parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
     565                         ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
     566                         ImDrawCmd:  'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
     567                     - 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.
     568                     - 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!
     569                     - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
     570 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
     571 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
     572 - 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.
     573 - 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
     574 - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry!
     575 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
     576 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
     577 - 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.
     578 - 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.
     579 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
     580 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
     581 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
     582 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
     583 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
     584 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
     585 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
     586 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
     587 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
     588 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
     589 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
     590 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
     591 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
     592 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
     593 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
     594 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
     595 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
     596 - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
     597                       - old:  const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..];
     598                       - new:  unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->TexId = YourTexIdentifier;
     599                       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.
     600 - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
     601 - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
     602 - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
     603 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
     604 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
     605 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
     606 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
     607 - 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)
     608 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
     609 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
     610 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
     611 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
     612 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
     613 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
     614
     615
     616 FREQUENTLY ASKED QUESTIONS (FAQ)
     617 ================================
     618
     619 Read all answers online:
     620   https://www.dearimgui.org/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url)
     621 Read all answers locally (with a text editor or ideally a Markdown viewer):
     622   docs/FAQ.md
     623 Some answers are copied down here to facilitate searching in code.
     624
     625 Q&A: Basics
     626 ===========
     627
     628 Q: Where is the documentation?
     629 A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
     630    - Run the examples/ and explore them.
     631    - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
     632    - The demo covers most features of Dear ImGui, so you can read the code and see its output.
     633    - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
     634    - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the
     635      examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
     636    - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.
     637    - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.
     638    - Your programming IDE is your friend, find the type or function declaration to find comments
     639      associated to it.
     640
     641 Q: What is this library called?
     642 Q: Which version should I get?
     643 >> This library is called "Dear ImGui", please don't call it "ImGui" :)
     644 >> See https://www.dearimgui.org/faq for details.
     645
     646 Q&A: Integration
     647 ================
     648
     649 Q: How to get started?
     650 A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt.
     651
     652 Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application?
     653 A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
     654 >> See https://www.dearimgui.org/faq for fully detailed answer. You really want to read this.
     655
     656 Q. How can I enable keyboard controls?
     657 Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
     658 Q: I integrated Dear ImGui in my engine and little squares are showing instead of text..
     659 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
     660 Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries..
     661 >> See https://www.dearimgui.org/faq
     662
     663 Q&A: Usage
     664 ----------
     665
     666 Q: Why is my widget not reacting when I click on it?
     667 Q: How can I have widgets with an empty label?
     668 Q: How can I have multiple widgets with the same label?
     669 Q: How can I display an image? What is ImTextureID, how does it works?
     670 Q: How can I use my own math types instead of ImVec2/ImVec4?
     671 Q: How can I interact with standard C++ types (such as std::string and std::vector)?
     672 Q: How can I display custom shapes? (using low-level ImDrawList API)
     673 >> See https://www.dearimgui.org/faq
     674
     675 Q&A: Fonts, Text
     676 ================
     677
     678 Q: How should I handle DPI in my application?
     679 Q: How can I load a different font than the default?
     680 Q: How can I easily use icons in my application?
     681 Q: How can I load multiple fonts?
     682 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
     683 >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md
     684
     685 Q&A: Concerns
     686 =============
     687
     688 Q: Who uses Dear ImGui?
     689 Q: Can you create elaborate/serious tools with Dear ImGui?
     690 Q: Can you reskin the look of Dear ImGui?
     691 Q: Why using C++ (as opposed to C)?
     692 >> See https://www.dearimgui.org/faq
     693
     694 Q&A: Community
     695 ==============
     696
     697 Q: How can I help?
     698 A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui!
     699      We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
     700      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.
     701    - Individuals: you can support continued development via PayPal donations. See README.
     702    - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt
     703      and see how you want to help and can help!
     704    - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
     705      You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/3488). Visuals are ideal as they inspire other programmers.
     706      But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
     707    - 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).
     708
     709*/
     710
     711//-------------------------------------------------------------------------
     712// [SECTION] INCLUDES
     713//-------------------------------------------------------------------------
    656714
    657715#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
     
    660718
    661719#include "imgui.h"
     720#ifndef IMGUI_DISABLE
     721
     722#ifndef IMGUI_DEFINE_MATH_OPERATORS
    662723#define IMGUI_DEFINE_MATH_OPERATORS
     724#endif
    663725#include "imgui_internal.h"
    664726
    665 #include <ctype.h>      // toupper, isprint
    666 #include <stdlib.h>     // NULL, malloc, free, qsort, atoi
     727// System includes
     728#include <ctype.h>      // toupper
    667729#include <stdio.h>      // vsnprintf, sscanf, printf
    668730#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
     
    672734#endif
    673735
    674 #define IMGUI_DEBUG_NAV_SCORING     0
    675 #define IMGUI_DEBUG_NAV_RECTS       0
     736// [Windows] OS specific includes (optional)
     737#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)
     738#define IMGUI_DISABLE_WIN32_FUNCTIONS
     739#endif
     740#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
     741#ifndef WIN32_LEAN_AND_MEAN
     742#define WIN32_LEAN_AND_MEAN
     743#endif
     744#ifndef NOMINMAX
     745#define NOMINMAX
     746#endif
     747#ifndef __MINGW32__
     748#include <Windows.h>        // _wfopen, OpenClipboard
     749#else
     750#include <windows.h>
     751#endif
     752#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions
     753#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
     754#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
     755#endif
     756#endif
     757
     758// [Apple] OS specific includes
     759#if defined(__APPLE__)
     760#include <TargetConditionals.h>
     761#endif
    676762
    677763// Visual Studio warnings
    678764#ifdef _MSC_VER
    679 #pragma warning (disable: 4127) // condition expression is constant
    680 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
    681 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
     765#pragma warning (disable: 4127)             // condition expression is constant
     766#pragma warning (disable: 4996)             // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
     767#if defined(_MSC_VER) && _MSC_VER >= 1922   // MSVC 2019 16.2 or later
     768#pragma warning (disable: 5054)             // operator '|': deprecated between enumerations of different types
    682769#endif
    683 
    684 // Clang warnings with -Weverything
    685 #ifdef __clang__
    686 #pragma clang diagnostic ignored "-Wunknown-pragmas"        // warning : unknown warning group '-Wformat-pedantic *'        // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great!
    687 #pragma clang diagnostic ignored "-Wold-style-cast"         // warning : use of old-style cast                              // yes, they are more terse.
    688 #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.
    689 #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.
    690 #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.
    691 #pragma clang diagnostic ignored "-Wglobal-constructors"    // warning : declaration requires a global destructor           // similar to above, not sure what the exact difference it.
    692 #pragma clang diagnostic ignored "-Wsign-conversion"        // warning : implicit conversion changes signedness             //
    693 #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.
    694 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
     770#endif
     771
     772// Clang/GCC warnings with -Weverything
     773#if defined(__clang__)
     774#if __has_warning("-Wunknown-warning-option")
     775#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!
     776#endif
     777#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
     778#pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                            // yes, they are more terse.
     779#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.
     780#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.
     781#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.
     782#pragma clang diagnostic ignored "-Wglobal-constructors"            // warning: declaration requires a global destructor         // similar to above, not sure what the exact difference is.
     783#pragma clang diagnostic ignored "-Wsign-conversion"                // warning: implicit conversion changes signedness
     784#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.
     785#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning: cast to 'void *' from smaller integer type 'int'
     786#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0
     787#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.
     788#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
    695789#elif defined(__GNUC__)
     790// We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association.
     791#pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
    696792#pragma GCC diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
    697793#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"      // warning: cast to pointer from integer of different size
     
    701797#pragma GCC diagnostic ignored "-Wformat-nonliteral"        // warning: format not a string literal, format string not checked
    702798#pragma GCC diagnostic ignored "-Wstrict-overflow"          // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
     799#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
    703800#endif
    704801
    705 // Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall
    706 #ifdef _MSC_VER
    707 #define IMGUI_CDECL __cdecl
    708 #else
    709 #define IMGUI_CDECL
    710 #endif
     802// Debug options
     803#define IMGUI_DEBUG_NAV_SCORING     0   // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL
     804#define IMGUI_DEBUG_NAV_RECTS       0   // Display the reference navigation rectangle for each window
     805#define IMGUI_DEBUG_INI_SETTINGS    0   // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower)
     806
     807// 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.
     808static const float NAV_WINDOWING_HIGHLIGHT_DELAY            = 0.20f;    // Time before the highlight and screen dimming starts fading in
     809static const float NAV_WINDOWING_LIST_APPEAR_DELAY          = 0.15f;    // Time before the window list starts to appear
     810
     811// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end)
     812static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f;     // Extend outside and inside windows. Affect FindHoveredWindow().
     813static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f;    // Reduce visual noise by only highlighting the border after a certain time.
     814static 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.
    711815
    712816//-------------------------------------------------------------------------
    713 // Forward Declarations
     817// [SECTION] FORWARD DECLARATIONS
    714818//-------------------------------------------------------------------------
    715819
    716 static bool             IsKeyPressedMap(ImGuiKey key, bool repeat = true);
    717 
    718 static ImFont*          GetDefaultFont();
    719820static void             SetCurrentWindow(ImGuiWindow* window);
    720 static void             SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
    721 static void             SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
    722 static void             SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond);
    723 static void             SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond);
    724 static void             SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond);
    725 static ImGuiWindow*     FindHoveredWindow();
    726 static ImGuiWindow*     CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags);
    727 static void             CheckStacksSize(ImGuiWindow* window, bool write);
     821static void             FindHoveredWindow();
     822static ImGuiWindow*     CreateNewWindow(const char* name, ImGuiWindowFlags flags);
    728823static ImVec2           CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);
    729824
    730825static void             AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
    731 static void             AddWindowToDrawData(ImVector<ImDrawList*>* out_list, ImGuiWindow* window);
    732 static void             AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
    733 
    734 static ImGuiWindowSettings* AddWindowSettings(const char* name);
    735 
    736 static void             LoadIniSettingsFromDisk(const char* ini_filename);
    737 static void             LoadIniSettingsFromMemory(const char* buf);
    738 static void             SaveIniSettingsToDisk(const char* ini_filename);
    739 static void             SaveIniSettingsToMemory(ImVector<char>& out_buf);
    740 static void             MarkIniSettingsDirty(ImGuiWindow* window);
     826static void             AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
    741827
    742828static ImRect           GetViewportRect();
    743829
    744 static void             ClosePopupToLevel(int remaining);
    745 
    746 static bool             InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data);
    747 static int              InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
    748 static ImVec2           InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
    749 
    750 static inline int       DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format);
    751 static void             DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2);
    752 static bool             DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format);
    753 
    754 namespace ImGui
    755 {
    756    static void             NavUpdate();
    757    static void             NavUpdateWindowing();
    758    static void             NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id);
    759 
    760    static void             UpdateMovingWindow();
    761    static void             UpdateMouseInputs();
    762    static void             UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
    763    static void             FocusFrontMostActiveWindow(ImGuiWindow* ignore_window);
    764 }
    765 
    766 //-----------------------------------------------------------------------------
    767 // Platform dependent default implementations
    768 //-----------------------------------------------------------------------------
    769 
     830// Settings
     831static void             WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);
     832static void*            WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
     833static void             WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
     834static void             WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
     835static void             WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
     836
     837// Platform Dependents default implementation for IO functions
    770838static const char*      GetClipboardTextFn_DefaultImpl(void* user_data);
    771839static void             SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
    772840static void             ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
    773841
     842namespace ImGui
     843{
     844// Navigation
     845static void             NavUpdate();
     846static void             NavUpdateWindowing();
     847static void             NavUpdateWindowingOverlay();
     848static void             NavUpdateMoveResult();
     849static void             NavUpdateInitResult();
     850static float            NavUpdatePageUpPageDown();
     851static inline void      NavUpdateAnyRequestFlag();
     852static void             NavEndFrame();
     853static bool             NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
     854static void             NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
     855static ImVec2           NavCalcPreferredRefPos();
     856static void             NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
     857static ImGuiWindow*     NavRestoreLastChildNavWindow(ImGuiWindow* window);
     858static int              FindWindowFocusIndex(ImGuiWindow* window);
     859
     860// Error Checking
     861static void             ErrorCheckNewFrameSanityChecks();
     862static void             ErrorCheckEndFrameSanityChecks();
     863static void             ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write);
     864
     865// Misc
     866static void             UpdateSettings();
     867static void             UpdateMouseInputs();
     868static void             UpdateMouseWheel();
     869static void             UpdateTabFocus();
     870static void             UpdateDebugToolItemPicker();
     871static 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);
     872static void             RenderWindowOuterBorders(ImGuiWindow* window);
     873static 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);
     874static void             RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
     875
     876}
     877
    774878//-----------------------------------------------------------------------------
    775 // Context
     879// [SECTION] CONTEXT AND MEMORY ALLOCATORS
    776880//-----------------------------------------------------------------------------
    777881
    778 // Current context pointer. Implicitly used by all ImGui functions. Always assumed to be != NULL.
    779 // CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
    780 // If you use DLL hotreloading you might need to call SetCurrentContext() after reloading code from this file.
    781 // ImGui functions are not thread-safe because of this pointer. If you want thread-safety to allow N threads to access N different contexts, you can:
    782 // - Change this variable to use thread local storage. You may #define GImGui in imconfig.h for that purpose. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
    783 // - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts)
     882// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
     883// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
     884// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call
     885//    SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading.
     886//    In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into.
     887// 2) Important: Dear ImGui functions are not thread-safe because of this pointer.
     888//    If you want thread-safety to allow N threads to access N different contexts, you can:
     889//    - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h:
     890//          struct ImGuiContext;
     891//          extern thread_local ImGuiContext* MyImGuiTLS;
     892//          #define GImGui MyImGuiTLS
     893//      And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
     894//    - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
     895//    - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace.
    784896#ifndef GImGui
    785897ImGuiContext*   GImGui = NULL;
     
    787899
    788900// Memory Allocator functions. Use SetAllocatorFunctions() to change them.
    789 // If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file. 
     901// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file.
    790902// Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
    791903#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
    792 static void*   MallocWrapper(size_t size, void* user_data) { (void)user_data; return malloc(size); }
    793 static void    FreeWrapper(void* ptr, void* user_data) { (void)user_data; free(ptr); }
     904static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); return malloc(size); }
     905static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); free(ptr); }
    794906#else
    795 static void*   MallocWrapper(size_t size, void* user_data) { (void)user_data; (void)size; IM_ASSERT(0); return NULL; }
    796 static void    FreeWrapper(void* ptr, void* user_data) { (void)user_data; (void)ptr; IM_ASSERT(0); }
     907static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
     908static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
    797909#endif
    798910
    799911static void*  (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
    800 static void(*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
     912static void   (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
    801913static void*    GImAllocatorUserData = NULL;
    802 static size_t   GImAllocatorActiveAllocationsCount = 0;
    803914
    804915//-----------------------------------------------------------------------------
    805 // User facing structures
     916// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
    806917//-----------------------------------------------------------------------------
    807918
    808919ImGuiStyle::ImGuiStyle()
    809920{
    810    Alpha = 1.0f;             // Global alpha applies to everything in ImGui
    811    WindowPadding = ImVec2(8, 8);      // Padding within a window
    812    WindowRounding = 7.0f;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows
    813    WindowBorderSize = 1.0f;             // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
    814    WindowMinSize = ImVec2(32, 32);    // Minimum window size
    815    WindowTitleAlign = ImVec2(0.0f, 0.5f);// Alignment for title bar text
    816    ChildRounding = 0.0f;             // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
    817    ChildBorderSize = 1.0f;             // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
    818    PopupRounding = 0.0f;             // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
    819    PopupBorderSize = 1.0f;             // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
    820    FramePadding = ImVec2(4, 3);      // Padding within a framed rectangle (used by most widgets)
    821    FrameRounding = 0.0f;             // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
    822    FrameBorderSize = 0.0f;             // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
    823    ItemSpacing = ImVec2(8, 4);      // Horizontal and vertical spacing between widgets/lines
    824    ItemInnerSpacing = ImVec2(4, 4);      // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
    825    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!
    826    IndentSpacing = 21.0f;            // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
    827    ColumnsMinSpacing = 6.0f;             // Minimum horizontal spacing between two columns
    828    ScrollbarSize = 16.0f;            // Width of the vertical scrollbar, Height of the horizontal scrollbar
    829    ScrollbarRounding = 9.0f;             // Radius of grab corners rounding for scrollbar
    830    GrabMinSize = 10.0f;            // Minimum width/height of a grab box for slider/scrollbar
    831    GrabRounding = 0.0f;             // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
    832    ButtonTextAlign = ImVec2(0.5f, 0.5f);// Alignment of button text when button is larger than text.
    833    DisplayWindowPadding = ImVec2(20, 20);    // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
    834    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.
    835    MouseCursorScale = 1.0f;             // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
    836    AntiAliasedLines = true;             // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
    837    AntiAliasedFill = true;             // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
    838    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.
    839 
    840                                             // Default theme
    841    ImGui::StyleColorsDark(this);
     921    Alpha                   = 1.0f;             // Global alpha applies to everything in ImGui
     922    WindowPadding           = ImVec2(8,8);      // Padding within a window
     923    WindowRounding          = 7.0f;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
     924    WindowBorderSize        = 1.0f;             // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
     925    WindowMinSize           = ImVec2(32,32);    // Minimum window size
     926    WindowTitleAlign        = ImVec2(0.0f,0.5f);// Alignment for title bar text
     927    WindowMenuButtonPosition= ImGuiDir_Left;    // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
     928    ChildRounding           = 0.0f;             // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
     929    ChildBorderSize         = 1.0f;             // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
     930    PopupRounding           = 0.0f;             // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
     931    PopupBorderSize         = 1.0f;             // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
     932    FramePadding            = ImVec2(4,3);      // Padding within a framed rectangle (used by most widgets)
     933    FrameRounding           = 0.0f;             // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
     934    FrameBorderSize         = 0.0f;             // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
     935    ItemSpacing             = ImVec2(8,4);      // Horizontal and vertical spacing between widgets/lines
     936    ItemInnerSpacing        = ImVec2(4,4);      // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
     937    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!
     938    IndentSpacing           = 21.0f;            // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
     939    ColumnsMinSpacing       = 6.0f;             // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
     940    ScrollbarSize           = 14.0f;            // Width of the vertical scrollbar, Height of the horizontal scrollbar
     941    ScrollbarRounding       = 9.0f;             // Radius of grab corners rounding for scrollbar
     942    GrabMinSize             = 10.0f;            // Minimum width/height of a grab box for slider/scrollbar
     943    GrabRounding            = 0.0f;             // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
     944    LogSliderDeadzone       = 4.0f;             // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
     945    TabRounding             = 4.0f;             // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
     946    TabBorderSize           = 0.0f;             // Thickness of border around tabs.
     947    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.
     948    ColorButtonPosition     = ImGuiDir_Right;   // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
     949    ButtonTextAlign         = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
     950    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.
     951    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.
     952    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.
     953    MouseCursorScale        = 1.0f;             // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
     954    AntiAliasedLines        = true;             // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
     955    AntiAliasedLinesUseTex  = true;             // Enable anti-aliased lines/borders using textures where possible. Require back-end to render with bilinear filtering.
     956    AntiAliasedFill         = true;             // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
     957    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.
     958    CircleSegmentMaxError   = 1.60f;            // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
     959
     960    // Default theme
     961    ImGui::StyleColorsDark(this);
    842962}
    843963
     
    846966void ImGuiStyle::ScaleAllSizes(float scale_factor)
    847967{
    848    WindowPadding = ImFloor(WindowPadding * scale_factor);
    849    WindowRounding = ImFloor(WindowRounding * scale_factor);
    850    WindowMinSize = ImFloor(WindowMinSize * scale_factor);
    851    ChildRounding = ImFloor(ChildRounding * scale_factor);
    852    PopupRounding = ImFloor(PopupRounding * scale_factor);
    853    FramePadding = ImFloor(FramePadding * scale_factor);
    854    FrameRounding = ImFloor(FrameRounding * scale_factor);
    855    ItemSpacing = ImFloor(ItemSpacing * scale_factor);
    856    ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
    857    TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
    858    IndentSpacing = ImFloor(IndentSpacing * scale_factor);
    859    ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
    860    ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
    861    ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
    862    GrabMinSize = ImFloor(GrabMinSize * scale_factor);
    863    GrabRounding = ImFloor(GrabRounding * scale_factor);
    864    DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
    865    DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
    866    MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
     968    WindowPadding = ImFloor(WindowPadding * scale_factor);
     969    WindowRounding = ImFloor(WindowRounding * scale_factor);
     970    WindowMinSize = ImFloor(WindowMinSize * scale_factor);
     971    ChildRounding = ImFloor(ChildRounding * scale_factor);
     972    PopupRounding = ImFloor(PopupRounding * scale_factor);
     973    FramePadding = ImFloor(FramePadding * scale_factor);
     974    FrameRounding = ImFloor(FrameRounding * scale_factor);
     975    ItemSpacing = ImFloor(ItemSpacing * scale_factor);
     976    ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
     977    TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
     978    IndentSpacing = ImFloor(IndentSpacing * scale_factor);
     979    ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
     980    ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
     981    ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
     982    GrabMinSize = ImFloor(GrabMinSize * scale_factor);
     983    GrabRounding = ImFloor(GrabRounding * scale_factor);
     984    LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor);
     985    TabRounding = ImFloor(TabRounding * scale_factor);
     986    TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImFloor(TabMinWidthForCloseButton * scale_factor) : FLT_MAX;
     987    DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
     988    DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
     989    MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
    867990}
    868991
    869992ImGuiIO::ImGuiIO()
    870993{
    871    // Most fields are initialized with zero
    872    memset(this, 0, sizeof(*this));
    873 
    874    // Settings
    875    ConfigFlags = 0x00;
    876    BackendFlags = 0x00;
    877    DisplaySize = ImVec2(-1.0f, -1.0f);
    878    DeltaTime = 1.0f / 60.0f;
    879    IniSavingRate = 5.0f;
    880    IniFilename = "imgui.ini";
    881    LogFilename = "imgui_log.txt";
    882    MouseDoubleClickTime = 0.30f;
    883    MouseDoubleClickMaxDist = 6.0f;
    884    for (int i = 0; i < ImGuiKey_COUNT; i++)
    885       KeyMap[i] = -1;
    886    KeyRepeatDelay = 0.250f;
    887    KeyRepeatRate = 0.050f;
    888    UserData = NULL;
    889 
    890    Fonts = NULL;
    891    FontGlobalScale = 1.0f;
    892    FontDefault = NULL;
    893    FontAllowUserScaling = false;
    894    DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
    895    DisplayVisibleMin = DisplayVisibleMax = ImVec2(0.0f, 0.0f);
    896 
    897    // Advanced/subtle behaviors
     994    // Most fields are initialized with zero
     995    memset(this, 0, sizeof(*this));
     996    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.
     997
     998    // Settings
     999    ConfigFlags = ImGuiConfigFlags_None;
     1000    BackendFlags = ImGuiBackendFlags_None;
     1001    DisplaySize = ImVec2(-1.0f, -1.0f);
     1002    DeltaTime = 1.0f / 60.0f;
     1003    IniSavingRate = 5.0f;
     1004    IniFilename = "imgui.ini";
     1005    LogFilename = "imgui_log.txt";
     1006    MouseDoubleClickTime = 0.30f;
     1007    MouseDoubleClickMaxDist = 6.0f;
     1008    for (int i = 0; i < ImGuiKey_COUNT; i++)
     1009        KeyMap[i] = -1;
     1010    KeyRepeatDelay = 0.275f;
     1011    KeyRepeatRate = 0.050f;
     1012    UserData = NULL;
     1013
     1014    Fonts = NULL;
     1015    FontGlobalScale = 1.0f;
     1016    FontDefault = NULL;
     1017    FontAllowUserScaling = false;
     1018    DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
     1019
     1020    // Miscellaneous options
     1021    MouseDrawCursor = false;
    8981022#ifdef __APPLE__
    899    OptMacOSXBehaviors = true;  // Set Mac OS X style defaults based on __APPLE__ compile time flag
     1023    ConfigMacOSXBehaviors = true;  // Set Mac OS X style defaults based on __APPLE__ compile time flag
    9001024#else
    901    OptMacOSXBehaviors = false;
     1025    ConfigMacOSXBehaviors = false;
    9021026#endif
    903    OptCursorBlink = true;
    904 
    905    // Settings (User Functions)
    906    GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;   // Platform dependent default implementations
    907    SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
    908    ClipboardUserData = NULL;
    909    ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
    910    ImeWindowHandle = NULL;
     1027    ConfigInputTextCursorBlink = true;
     1028    ConfigWindowsResizeFromEdges = true;
     1029    ConfigWindowsMoveFromTitleBarOnly = false;
     1030    ConfigWindowsMemoryCompactTimer = 60.0f;
     1031
     1032    // Platform Functions
     1033    BackendPlatformName = BackendRendererName = NULL;
     1034    BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
     1035    GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;   // Platform dependent default implementations
     1036    SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
     1037    ClipboardUserData = NULL;
     1038    ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
     1039    ImeWindowHandle = NULL;
    9111040
    9121041#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    913    RenderDrawListsFn = NULL;
     1042    RenderDrawListsFn = NULL;
    9141043#endif
    9151044
    916    // Input (NB: we already have memset zero the entire structure)
    917    MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
    918    MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
    919    MouseDragThreshold = 6.0f;
    920    for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
    921    for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f;
    922    for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
     1045    // Input (NB: we already have memset zero the entire structure!)
     1046    MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
     1047    MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
     1048    MouseDragThreshold = 6.0f;
     1049    for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
     1050    for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f;
     1051    for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
    9231052}
    9241053
     
    9261055// - with glfw you can get those from the callback set in glfwSetCharCallback()
    9271056// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
    928 void ImGuiIO::AddInputCharacter(ImWchar c)
    929 {
    930    const int n = ImStrlenW(InputCharacters);
    931    if (n + 1 < IM_ARRAYSIZE(InputCharacters))
    932    {
    933       InputCharacters[n] = c;
    934       InputCharacters[n + 1] = '\0';
    935    }
     1057void ImGuiIO::AddInputCharacter(unsigned int c)
     1058{
     1059    if (c != 0)
     1060        InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
     1061}
     1062
     1063// UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
     1064// we should save the high surrogate.
     1065void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
     1066{
     1067    if (c == 0 && InputQueueSurrogate == 0)
     1068        return;
     1069
     1070    if ((c & 0xFC00) == 0xD800) // High surrogate, must save
     1071    {
     1072        if (InputQueueSurrogate != 0)
     1073            InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
     1074        InputQueueSurrogate = c;
     1075        return;
     1076    }
     1077
     1078    ImWchar cp = c;
     1079    if (InputQueueSurrogate != 0)
     1080    {
     1081        if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
     1082            InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
     1083        else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) // Codepoint will not fit in ImWchar (extra parenthesis around 0xFFFF somehow fixes -Wunreachable-code with Clang)
     1084            cp = IM_UNICODE_CODEPOINT_INVALID;
     1085        else
     1086            cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
     1087        InputQueueSurrogate = 0;
     1088    }
     1089    InputQueueCharacters.push_back(cp);
    9361090}
    9371091
    9381092void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
    9391093{
    940    // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more
    941    const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar);
    942    ImWchar wchars[wchars_buf_len];
    943    ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL);
    944    for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++)
    945       AddInputCharacter(wchars[i]);
     1094    while (*utf8_chars != 0)
     1095    {
     1096        unsigned int c = 0;
     1097        utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
     1098        if (c != 0)
     1099            InputQueueCharacters.push_back((ImWchar)c);
     1100    }
     1101}
     1102
     1103void ImGuiIO::ClearInputCharacters()
     1104{
     1105    InputQueueCharacters.resize(0);
    9461106}
    9471107
    9481108//-----------------------------------------------------------------------------
    949 // HELPERS
     1109// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
    9501110//-----------------------------------------------------------------------------
    9511111
    952 #define IM_F32_TO_INT8_UNBOUND(_VAL)    ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f)))   // Unsaturated, for display purpose
    953 #define IM_F32_TO_INT8_SAT(_VAL)        ((int)(ImSaturate(_VAL) * 255.0f + 0.5f))               // Saturated, always output 0..255
     1112ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
     1113{
     1114    IM_ASSERT(num_segments > 0); // Use ImBezierClosestPointCasteljau()
     1115    ImVec2 p_last = p1;
     1116    ImVec2 p_closest;
     1117    float p_closest_dist2 = FLT_MAX;
     1118    float t_step = 1.0f / (float)num_segments;
     1119    for (int i_step = 1; i_step <= num_segments; i_step++)
     1120    {
     1121        ImVec2 p_current = ImBezierCalc(p1, p2, p3, p4, t_step * i_step);
     1122        ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
     1123        float dist2 = ImLengthSqr(p - p_line);
     1124        if (dist2 < p_closest_dist2)
     1125        {
     1126            p_closest = p_line;
     1127            p_closest_dist2 = dist2;
     1128        }
     1129        p_last = p_current;
     1130    }
     1131    return p_closest;
     1132}
     1133
     1134// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp
     1135static void BezierClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
     1136{
     1137    float dx = x4 - x1;
     1138    float dy = y4 - y1;
     1139    float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
     1140    float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
     1141    d2 = (d2 >= 0) ? d2 : -d2;
     1142    d3 = (d3 >= 0) ? d3 : -d3;
     1143    if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
     1144    {
     1145        ImVec2 p_current(x4, y4);
     1146        ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
     1147        float dist2 = ImLengthSqr(p - p_line);
     1148        if (dist2 < p_closest_dist2)
     1149        {
     1150            p_closest = p_line;
     1151            p_closest_dist2 = dist2;
     1152        }
     1153        p_last = p_current;
     1154    }
     1155    else if (level < 10)
     1156    {
     1157        float x12 = (x1 + x2)*0.5f,       y12 = (y1 + y2)*0.5f;
     1158        float x23 = (x2 + x3)*0.5f,       y23 = (y2 + y3)*0.5f;
     1159        float x34 = (x3 + x4)*0.5f,       y34 = (y3 + y4)*0.5f;
     1160        float x123 = (x12 + x23)*0.5f,    y123 = (y12 + y23)*0.5f;
     1161        float x234 = (x23 + x34)*0.5f,    y234 = (y23 + y34)*0.5f;
     1162        float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
     1163        BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
     1164        BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
     1165    }
     1166}
     1167
     1168// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol
     1169// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.
     1170ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
     1171{
     1172    IM_ASSERT(tess_tol > 0.0f);
     1173    ImVec2 p_last = p1;
     1174    ImVec2 p_closest;
     1175    float p_closest_dist2 = FLT_MAX;
     1176    BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
     1177    return p_closest;
     1178}
    9541179
    9551180ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
    9561181{
    957    ImVec2 ap = p - a;
    958    ImVec2 ab_dir = b - a;
    959    float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
    960    if (dot < 0.0f)
    961       return a;
    962    float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
    963    if (dot > ab_len_sqr)
    964       return b;
    965    return a + ab_dir * dot / ab_len_sqr;
     1182    ImVec2 ap = p - a;
     1183    ImVec2 ab_dir = b - a;
     1184    float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
     1185    if (dot < 0.0f)
     1186        return a;
     1187    float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
     1188    if (dot > ab_len_sqr)
     1189        return b;
     1190    return a + ab_dir * dot / ab_len_sqr;
    9661191}
    9671192
    9681193bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
    9691194{
    970    bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
    971    bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
    972    bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
    973    return ((b1 == b2) && (b2 == b3));
     1195    bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
     1196    bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
     1197    bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
     1198    return ((b1 == b2) && (b2 == b3));
    9741199}
    9751200
    9761201void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
    9771202{
    978    ImVec2 v0 = b - a;
    979    ImVec2 v1 = c - a;
    980    ImVec2 v2 = p - a;
    981    const float denom = v0.x * v1.y - v1.x * v0.y;
    982    out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
    983    out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
    984    out_u = 1.0f - out_v - out_w;
     1203    ImVec2 v0 = b - a;
     1204    ImVec2 v1 = c - a;
     1205    ImVec2 v2 = p - a;
     1206    const float denom = v0.x * v1.y - v1.x * v0.y;
     1207    out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
     1208    out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
     1209    out_u = 1.0f - out_v - out_w;
    9851210}
    9861211
    9871212ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
    9881213{
    989    ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
    990    ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
    991    ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
    992    float dist2_ab = ImLengthSqr(p - proj_ab);
    993    float dist2_bc = ImLengthSqr(p - proj_bc);
    994    float dist2_ca = ImLengthSqr(p - proj_ca);
    995    float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
    996    if (m == dist2_ab)
    997       return proj_ab;
    998    if (m == dist2_bc)
    999       return proj_bc;
    1000    return proj_ca;
    1001 }
    1002 
     1214    ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
     1215    ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
     1216    ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
     1217    float dist2_ab = ImLengthSqr(p - proj_ab);
     1218    float dist2_bc = ImLengthSqr(p - proj_bc);
     1219    float dist2_ca = ImLengthSqr(p - proj_ca);
     1220    float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
     1221    if (m == dist2_ab)
     1222        return proj_ab;
     1223    if (m == dist2_bc)
     1224        return proj_bc;
     1225    return proj_ca;
     1226}
     1227
     1228//-----------------------------------------------------------------------------
     1229// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
     1230//-----------------------------------------------------------------------------
     1231
     1232// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
    10031233int ImStricmp(const char* str1, const char* str2)
    10041234{
    1005    int d;
    1006    while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
    1007    return d;
     1235    int d;
     1236    while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
     1237    return d;
    10081238}
    10091239
    10101240int ImStrnicmp(const char* str1, const char* str2, size_t count)
    10111241{
    1012    int d = 0;
    1013    while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
    1014    return d;
     1242    int d = 0;
     1243    while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
     1244    return d;
    10151245}
    10161246
    10171247void ImStrncpy(char* dst, const char* src, size_t count)
    10181248{
    1019    if (count < 1) return;
    1020    strncpy(dst, src, count);
    1021    dst[count - 1] = 0;
    1022 }
    1023 
    1024 char* ImStrdup(const char *str)
    1025 {
    1026    size_t len = strlen(str) + 1;
    1027    void* buf = ImGui::MemAlloc(len);
    1028    return (char*)memcpy(buf, (const void*)str, len);
     1249    if (count < 1)
     1250        return;
     1251    if (count > 1)
     1252        strncpy(dst, src, count - 1);
     1253    dst[count - 1] = 0;
     1254}
     1255
     1256char* ImStrdup(const char* str)
     1257{
     1258    size_t len = strlen(str);
     1259    void* buf = IM_ALLOC(len + 1);
     1260    return (char*)memcpy(buf, (const void*)str, len + 1);
     1261}
     1262
     1263char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
     1264{
     1265    size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
     1266    size_t src_size = strlen(src) + 1;
     1267    if (dst_buf_size < src_size)
     1268    {
     1269        IM_FREE(dst);
     1270        dst = (char*)IM_ALLOC(src_size);
     1271        if (p_dst_size)
     1272            *p_dst_size = src_size;
     1273    }
     1274    return (char*)memcpy(dst, (const void*)src, src_size);
    10291275}
    10301276
    10311277const char* ImStrchrRange(const char* str, const char* str_end, char c)
    10321278{
    1033    for (; str < str_end; str++)
    1034       if (*str == c)
    1035          return str;
    1036    return NULL;
     1279    const char* p = (const char*)memchr(str, (int)c, str_end - str);
     1280    return p;
    10371281}
    10381282
    10391283int ImStrlenW(const ImWchar* str)
    10401284{
    1041    int n = 0;
    1042    while (*str++) n++;
    1043    return n;
     1285    //return (int)wcslen((const wchar_t*)str);  // FIXME-OPT: Could use this when wchar_t are 16-bit
     1286    int n = 0;
     1287    while (*str++) n++;
     1288    return n;
     1289}
     1290
     1291// Find end-of-line. Return pointer will point to either first \n, either str_end.
     1292const char* ImStreolRange(const char* str, const char* str_end)
     1293{
     1294    const char* p = (const char*)memchr(str, '\n', str_end - str);
     1295    return p ? p : str_end;
    10441296}
    10451297
    10461298const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
    10471299{
    1048    while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
    1049       buf_mid_line--;
    1050    return buf_mid_line;
     1300    while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
     1301        buf_mid_line--;
     1302    return buf_mid_line;
    10511303}
    10521304
    10531305const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
    10541306{
    1055    if (!needle_end)
    1056       needle_end = needle + strlen(needle);
    1057 
    1058    const char un0 = (char)toupper(*needle);
    1059    while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
    1060    {
    1061       if (toupper(*haystack) == un0)
    1062       {
    1063          const char* b = needle + 1;
    1064          for (const char* a = haystack + 1; b < needle_end; a++, b++)
    1065             if (toupper(*a) != toupper(*b))
    1066                break;
    1067          if (b == needle_end)
    1068             return haystack;
    1069       }
    1070       haystack++;
    1071    }
    1072    return NULL;
    1073 }
    1074 
    1075 static const char* ImAtoi(const char* src, int* output)
    1076 {
    1077    int negative = 0;
    1078    if (*src == '-') { negative = 1; src++; }
    1079    if (*src == '+') { src++; }
    1080    int v = 0;
    1081    while (*src >= '0' && *src <= '9')
    1082       v = (v * 10) + (*src++ - '0');
    1083    *output = negative ? -v : v;
    1084    return src;
    1085 }
    1086 
    1087 // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
     1307    if (!needle_end)
     1308        needle_end = needle + strlen(needle);
     1309
     1310    const char un0 = (char)toupper(*needle);
     1311    while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
     1312    {
     1313        if (toupper(*haystack) == un0)
     1314        {
     1315            const char* b = needle + 1;
     1316            for (const char* a = haystack + 1; b < needle_end; a++, b++)
     1317                if (toupper(*a) != toupper(*b))
     1318                    break;
     1319            if (b == needle_end)
     1320                return haystack;
     1321        }
     1322        haystack++;
     1323    }
     1324    return NULL;
     1325}
     1326
     1327// 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.
     1328void ImStrTrimBlanks(char* buf)
     1329{
     1330    char* p = buf;
     1331    while (p[0] == ' ' || p[0] == '\t')     // Leading blanks
     1332        p++;
     1333    char* p_start = p;
     1334    while (*p != 0)                         // Find end of string
     1335        p++;
     1336    while (p > p_start && (p[-1] == ' ' || p[-1] == '\t'))  // Trailing blanks
     1337        p--;
     1338    if (p_start != buf)                     // Copy memory if we had leading blanks
     1339        memmove(buf, p_start, p - p_start);
     1340    buf[p - p_start] = 0;                   // Zero terminate
     1341}
     1342
     1343const char* ImStrSkipBlank(const char* str)
     1344{
     1345    while (str[0] == ' ' || str[0] == '\t')
     1346        str++;
     1347    return str;
     1348}
     1349
     1350// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
    10881351// 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.
    10891352// B) When buf==NULL vsnprintf() will return the output size.
    1090 #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
     1353#ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
     1354
     1355// We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)
     1356// You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
     1357// and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are
     1358// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
     1359#ifdef IMGUI_USE_STB_SPRINTF
     1360#define STB_SPRINTF_IMPLEMENTATION
     1361#include "stb_sprintf.h"
     1362#endif
     1363
     1364#if defined(_MSC_VER) && !defined(vsnprintf)
     1365#define vsnprintf _vsnprintf
     1366#endif
     1367
    10911368int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
    10921369{
    1093    va_list args;
    1094    va_start(args, fmt);
    1095    int w = vsnprintf(buf, buf_size, fmt, args);
    1096    va_end(args);
    1097    if (buf == NULL)
    1098       return w;
    1099    if (w == -1 || w >= (int)buf_size)
    1100       w = (int)buf_size - 1;
    1101    buf[w] = 0;
    1102    return w;
     1370    va_list args;
     1371    va_start(args, fmt);
     1372#ifdef IMGUI_USE_STB_SPRINTF
     1373    int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
     1374#else
     1375    int w = vsnprintf(buf, buf_size, fmt, args);
     1376#endif
     1377    va_end(args);
     1378    if (buf == NULL)
     1379        return w;
     1380    if (w == -1 || w >= (int)buf_size)
     1381        w = (int)buf_size - 1;
     1382    buf[w] = 0;
     1383    return w;
    11031384}
    11041385
    11051386int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
    11061387{
    1107    int w = vsnprintf(buf, buf_size, fmt, args);
    1108    if (buf == NULL)
    1109       return w;
    1110    if (w == -1 || w >= (int)buf_size)
    1111       w = (int)buf_size - 1;
    1112    buf[w] = 0;
    1113    return w;
    1114 }
    1115 #endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
    1116 
    1117 // Pass data_size==0 for zero-terminated strings
     1388#ifdef IMGUI_USE_STB_SPRINTF
     1389    int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
     1390#else
     1391    int w = vsnprintf(buf, buf_size, fmt, args);
     1392#endif
     1393    if (buf == NULL)
     1394        return w;
     1395    if (w == -1 || w >= (int)buf_size)
     1396        w = (int)buf_size - 1;
     1397    buf[w] = 0;
     1398    return w;
     1399}
     1400#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
     1401
     1402// CRC32 needs a 1KB lookup table (not cache friendly)
     1403// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
     1404// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
     1405static const ImU32 GCrc32LookupTable[256] =
     1406{
     1407    0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
     1408    0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
     1409    0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
     1410    0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
     1411    0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
     1412    0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
     1413    0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
     1414    0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
     1415    0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
     1416    0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
     1417    0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
     1418    0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
     1419    0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
     1420    0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
     1421    0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
     1422    0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
     1423};
     1424
     1425// Known size hash
     1426// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
    11181427// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
    1119 ImU32 ImHash(const void* data, int data_size, ImU32 seed)
    1120 {
    1121    static ImU32 crc32_lut[256] = { 0 };
    1122    if (!crc32_lut[1])
    1123    {
    1124       const ImU32 polynomial = 0xEDB88320;
    1125       for (ImU32 i = 0; i < 256; i++)
    1126       {
    1127          ImU32 crc = i;
    1128          for (ImU32 j = 0; j < 8; j++)
    1129             crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial);
    1130          crc32_lut[i] = crc;
    1131       }
    1132    }
    1133 
    1134    seed = ~seed;
    1135    ImU32 crc = seed;
    1136    const unsigned char* current = (const unsigned char*)data;
    1137 
    1138    if (data_size > 0)
    1139    {
    1140       // Known size
    1141       while (data_size--)
    1142          crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++];
    1143    }
    1144    else
    1145    {
    1146       // Zero-terminated string
    1147       while (unsigned char c = *current++)
    1148       {
    1149          // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
    1150          // Because this syntax is rarely used we are optimizing for the common case.
    1151          // - If we reach ### in the string we discard the hash so far and reset to the seed.
    1152          // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
    1153          if (c == '#' && current[0] == '#' && current[1] == '#')
    1154             crc = seed;
    1155          crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
    1156       }
    1157    }
    1158    return ~crc;
     1428ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed)
     1429{
     1430    ImU32 crc = ~seed;
     1431    const unsigned char* data = (const unsigned char*)data_p;
     1432    const ImU32* crc32_lut = GCrc32LookupTable;
     1433    while (data_size-- != 0)
     1434        crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
     1435    return ~crc;
     1436}
     1437
     1438// Zero-terminated string hash, with support for ### to reset back to seed value
     1439// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
     1440// Because this syntax is rarely used we are optimizing for the common case.
     1441// - If we reach ### in the string we discard the hash so far and reset to the seed.
     1442// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
     1443// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
     1444ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed)
     1445{
     1446    seed = ~seed;
     1447    ImU32 crc = seed;
     1448    const unsigned char* data = (const unsigned char*)data_p;
     1449    const ImU32* crc32_lut = GCrc32LookupTable;
     1450    if (data_size != 0)
     1451    {
     1452        while (data_size-- != 0)
     1453        {
     1454            unsigned char c = *data++;
     1455            if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
     1456                crc = seed;
     1457            crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
     1458        }
     1459    }
     1460    else
     1461    {
     1462        while (unsigned char c = *data++)
     1463        {
     1464            if (c == '#' && data[0] == '#' && data[1] == '#')
     1465                crc = seed;
     1466            crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
     1467        }
     1468    }
     1469    return ~crc;
    11591470}
    11601471
    11611472//-----------------------------------------------------------------------------
    1162 // ImText* helpers
     1473// [SECTION] MISC HELPERS/UTILITIES (File functions)
    11631474//-----------------------------------------------------------------------------
    11641475
    1165 // Convert UTF-8 to 32-bits character, process single character input.
     1476// Default file functions
     1477#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
     1478
     1479ImFileHandle ImFileOpen(const char* filename, const char* mode)
     1480{
     1481#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
     1482    // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
     1483    // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
     1484    const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
     1485    const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
     1486    ImVector<ImWchar> buf;
     1487    buf.resize(filename_wsize + mode_wsize);
     1488    ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
     1489    ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
     1490    return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]);
     1491#else
     1492    return fopen(filename, mode);
     1493#endif
     1494}
     1495
     1496// 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.
     1497bool    ImFileClose(ImFileHandle f)     { return fclose(f) == 0; }
     1498ImU64   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; }
     1499ImU64   ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f)           { return fread(data, (size_t)sz, (size_t)count, f); }
     1500ImU64   ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f)    { return fwrite(data, (size_t)sz, (size_t)count, f); }
     1501#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
     1502
     1503// Helper: Load file content into memory
     1504// Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
     1505// This can't really be used with "rt" because fseek size won't match read size.
     1506void*   ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
     1507{
     1508    IM_ASSERT(filename && mode);
     1509    if (out_file_size)
     1510        *out_file_size = 0;
     1511
     1512    ImFileHandle f;
     1513    if ((f = ImFileOpen(filename, mode)) == NULL)
     1514        return NULL;
     1515
     1516    size_t file_size = (size_t)ImFileGetSize(f);
     1517    if (file_size == (size_t)-1)
     1518    {
     1519        ImFileClose(f);
     1520        return NULL;
     1521    }
     1522
     1523    void* file_data = IM_ALLOC(file_size + padding_bytes);
     1524    if (file_data == NULL)
     1525    {
     1526        ImFileClose(f);
     1527        return NULL;
     1528    }
     1529    if (ImFileRead(file_data, 1, file_size, f) != file_size)
     1530    {
     1531        ImFileClose(f);
     1532        IM_FREE(file_data);
     1533        return NULL;
     1534    }
     1535    if (padding_bytes > 0)
     1536        memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
     1537
     1538    ImFileClose(f);
     1539    if (out_file_size)
     1540        *out_file_size = file_size;
     1541
     1542    return file_data;
     1543}
     1544
     1545//-----------------------------------------------------------------------------
     1546// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
     1547//-----------------------------------------------------------------------------
     1548
     1549// Convert UTF-8 to 32-bit character, process single character input.
    11661550// Based on stb_from_utf8() from github.com/nothings/stb/
    11671551// We handle UTF-8 decoding error by skipping forward.
    11681552int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
    11691553{
    1170    unsigned int c = (unsigned int)-1;
    1171    const unsigned char* str = (const unsigned char*)in_text;
    1172    if (!(*str & 0x80))
    1173    {
    1174       c = (unsigned int)(*str++);
    1175       *out_char = c;
    1176       return 1;
    1177    }
    1178    if ((*str & 0xe0) == 0xc0)
    1179    {
    1180       *out_char = 0xFFFD; // will be invalid but not end of string
    1181       if (in_text_end && in_text_end - (const char*)str < 2) return 1;
    1182       if (*str < 0xc2) return 2;
    1183       c = (unsigned int)((*str++ & 0x1f) << 6);
    1184       if ((*str & 0xc0) != 0x80) return 2;
    1185       c += (*str++ & 0x3f);
    1186       *out_char = c;
    1187       return 2;
    1188    }
    1189    if ((*str & 0xf0) == 0xe0)
    1190    {
    1191       *out_char = 0xFFFD; // will be invalid but not end of string
    1192       if (in_text_end && in_text_end - (const char*)str < 3) return 1;
    1193       if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
    1194       if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
    1195       c = (unsigned int)((*str++ & 0x0f) << 12);
    1196       if ((*str & 0xc0) != 0x80) return 3;
    1197       c += (unsigned int)((*str++ & 0x3f) << 6);
    1198       if ((*str & 0xc0) != 0x80) return 3;
    1199       c += (*str++ & 0x3f);
    1200       *out_char = c;
    1201       return 3;
    1202    }
    1203    if ((*str & 0xf8) == 0xf0)
    1204    {
    1205       *out_char = 0xFFFD; // will be invalid but not end of string
    1206       if (in_text_end && in_text_end - (const char*)str < 4) return 1;
    1207       if (*str > 0xf4) return 4;
    1208       if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
    1209       if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
    1210       c = (unsigned int)((*str++ & 0x07) << 18);
    1211       if ((*str & 0xc0) != 0x80) return 4;
    1212       c += (unsigned int)((*str++ & 0x3f) << 12);
    1213       if ((*str & 0xc0) != 0x80) return 4;
    1214       c += (unsigned int)((*str++ & 0x3f) << 6);
    1215       if ((*str & 0xc0) != 0x80) return 4;
    1216       c += (*str++ & 0x3f);
    1217       // utf-8 encodings of values used in surrogate pairs are invalid
    1218       if ((c & 0xFFFFF800) == 0xD800) return 4;
    1219       *out_char = c;
    1220       return 4;
    1221    }
    1222    *out_char = 0;
    1223    return 0;
     1554    unsigned int c = (unsigned int)-1;
     1555    const unsigned char* str = (const unsigned char*)in_text;
     1556    if (!(*str & 0x80))
     1557    {
     1558        c = (unsigned int)(*str++);
     1559        *out_char = c;
     1560        return 1;
     1561    }
     1562    if ((*str & 0xe0) == 0xc0)
     1563    {
     1564        *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
     1565        if (in_text_end && in_text_end - (const char*)str < 2) return 1;
     1566        if (*str < 0xc2) return 2;
     1567        c = (unsigned int)((*str++ & 0x1f) << 6);
     1568        if ((*str & 0xc0) != 0x80) return 2;
     1569        c += (*str++ & 0x3f);
     1570        *out_char = c;
     1571        return 2;
     1572    }
     1573    if ((*str & 0xf0) == 0xe0)
     1574    {
     1575        *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
     1576        if (in_text_end && in_text_end - (const char*)str < 3) return 1;
     1577        if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
     1578        if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
     1579        c = (unsigned int)((*str++ & 0x0f) << 12);
     1580        if ((*str & 0xc0) != 0x80) return 3;
     1581        c += (unsigned int)((*str++ & 0x3f) << 6);
     1582        if ((*str & 0xc0) != 0x80) return 3;
     1583        c += (*str++ & 0x3f);
     1584        *out_char = c;
     1585        return 3;
     1586    }
     1587    if ((*str & 0xf8) == 0xf0)
     1588    {
     1589        *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
     1590        if (in_text_end && in_text_end - (const char*)str < 4) return 1;
     1591        if (*str > 0xf4) return 4;
     1592        if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
     1593        if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
     1594        c = (unsigned int)((*str++ & 0x07) << 18);
     1595        if ((*str & 0xc0) != 0x80) return 4;
     1596        c += (unsigned int)((*str++ & 0x3f) << 12);
     1597        if ((*str & 0xc0) != 0x80) return 4;
     1598        c += (unsigned int)((*str++ & 0x3f) << 6);
     1599        if ((*str & 0xc0) != 0x80) return 4;
     1600        c += (*str++ & 0x3f);
     1601        // utf-8 encodings of values used in surrogate pairs are invalid
     1602        if ((c & 0xFFFFF800) == 0xD800) return 4;
     1603        // If codepoint does not fit in ImWchar, use replacement character U+FFFD instead
     1604        if (c > IM_UNICODE_CODEPOINT_MAX) c = IM_UNICODE_CODEPOINT_INVALID;
     1605        *out_char = c;
     1606        return 4;
     1607    }
     1608    *out_char = 0;
     1609    return 0;
    12241610}
    12251611
    12261612int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
    12271613{
    1228    ImWchar* buf_out = buf;
    1229    ImWchar* buf_end = buf + buf_size;
    1230    while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
    1231    {
    1232       unsigned int c;
    1233       in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
    1234       if (c == 0)
    1235          break;
    1236       if (c < 0x10000)    // FIXME: Losing characters that don't fit in 2 bytes
    1237          *buf_out++ = (ImWchar)c;
    1238    }
    1239    *buf_out = 0;
    1240    if (in_text_remaining)
    1241       *in_text_remaining = in_text;
    1242    return (int)(buf_out - buf);
     1614    ImWchar* buf_out = buf;
     1615    ImWchar* buf_end = buf + buf_size;
     1616    while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
     1617    {
     1618        unsigned int c;
     1619        in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
     1620        if (c == 0)
     1621            break;
     1622        *buf_out++ = (ImWchar)c;
     1623    }
     1624    *buf_out = 0;
     1625    if (in_text_remaining)
     1626        *in_text_remaining = in_text;
     1627    return (int)(buf_out - buf);
    12431628}
    12441629
    12451630int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
    12461631{
    1247    int char_count = 0;
    1248    while ((!in_text_end || in_text < in_text_end) && *in_text)
    1249    {
    1250       unsigned int c;
    1251       in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
    1252       if (c == 0)
    1253          break;
    1254       if (c < 0x10000)
    1255          char_count++;
    1256    }
    1257    return char_count;
     1632    int char_count = 0;
     1633    while ((!in_text_end || in_text < in_text_end) && *in_text)
     1634    {
     1635        unsigned int c;
     1636        in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
     1637        if (c == 0)
     1638            break;
     1639        char_count++;
     1640    }
     1641    return char_count;
    12581642}
    12591643
     
    12611645static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
    12621646{
    1263    if (c < 0x80)
    1264    {
    1265       buf[0] = (char)c;
    1266       return 1;
    1267    }
    1268    if (c < 0x800)
    1269    {
    1270       if (buf_size < 2) return 0;
    1271       buf[0] = (char)(0xc0 + (c >> 6));
    1272       buf[1] = (char)(0x80 + (c & 0x3f));
    1273       return 2;
    1274    }
    1275    if (c >= 0xdc00 && c < 0xe000)
    1276    {
    1277       return 0;
    1278    }
    1279    if (c >= 0xd800 && c < 0xdc00)
    1280    {
    1281       if (buf_size < 4) return 0;
    1282       buf[0] = (char)(0xf0 + (c >> 18));
    1283       buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
    1284       buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
    1285       buf[3] = (char)(0x80 + ((c) & 0x3f));
    1286       return 4;
    1287    }
    1288    //else if (c < 0x10000)
    1289    {
    1290       if (buf_size < 3) return 0;
    1291       buf[0] = (char)(0xe0 + (c >> 12));
    1292       buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
    1293       buf[2] = (char)(0x80 + ((c) & 0x3f));
    1294       return 3;
    1295    }
     1647    if (c < 0x80)
     1648    {
     1649        buf[0] = (char)c;
     1650        return 1;
     1651    }
     1652    if (c < 0x800)
     1653    {
     1654        if (buf_size < 2) return 0;
     1655        buf[0] = (char)(0xc0 + (c >> 6));
     1656        buf[1] = (char)(0x80 + (c & 0x3f));
     1657        return 2;
     1658    }
     1659    if (c < 0x10000)
     1660    {
     1661        if (buf_size < 3) return 0;
     1662        buf[0] = (char)(0xe0 + (c >> 12));
     1663        buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
     1664        buf[2] = (char)(0x80 + ((c ) & 0x3f));
     1665        return 3;
     1666    }
     1667    if (c <= 0x10FFFF)
     1668    {
     1669        if (buf_size < 4) return 0;
     1670        buf[0] = (char)(0xf0 + (c >> 18));
     1671        buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
     1672        buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
     1673        buf[3] = (char)(0x80 + ((c ) & 0x3f));
     1674        return 4;
     1675    }
     1676    // Invalid code point, the max unicode is 0x10FFFF
     1677    return 0;
     1678}
     1679
     1680// Not optimal but we very rarely use this function.
     1681int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
     1682{
     1683    unsigned int unused = 0;
     1684    return ImTextCharFromUtf8(&unused, in_text, in_text_end);
    12961685}
    12971686
    12981687static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
    12991688{
    1300    if (c < 0x80) return 1;
    1301    if (c < 0x800) return 2;
    1302    if (c >= 0xdc00 && c < 0xe000) return 0;
    1303    if (c >= 0xd800 && c < 0xdc00) return 4;
    1304    return 3;
     1689    if (c < 0x80) return 1;
     1690    if (c < 0x800) return 2;
     1691    if (c < 0x10000) return 3;
     1692    if (c <= 0x10FFFF) return 4;
     1693    return 3;
    13051694}
    13061695
    13071696int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
    13081697{
    1309    char* buf_out = buf;
    1310    const char* buf_end = buf + buf_size;
    1311    while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
    1312    {
    1313       unsigned int c = (unsigned int)(*in_text++);
    1314       if (c < 0x80)
    1315          *buf_out++ = (char)c;
    1316       else
    1317          buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);
    1318    }
    1319    *buf_out = 0;
    1320    return (int)(buf_out - buf);
     1698    char* buf_out = buf;
     1699    const char* buf_end = buf + buf_size;
     1700    while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
     1701    {
     1702        unsigned int c = (unsigned int)(*in_text++);
     1703        if (c < 0x80)
     1704            *buf_out++ = (char)c;
     1705        else
     1706            buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);
     1707    }
     1708    *buf_out = 0;
     1709    return (int)(buf_out - buf);
    13211710}
    13221711
    13231712int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
    13241713{
    1325    int bytes_count = 0;
    1326    while ((!in_text_end || in_text < in_text_end) && *in_text)
    1327    {
    1328       unsigned int c = (unsigned int)(*in_text++);
    1329       if (c < 0x80)
    1330          bytes_count++;
    1331       else
    1332          bytes_count += ImTextCountUtf8BytesFromChar(c);
    1333    }
    1334    return bytes_count;
     1714    int bytes_count = 0;
     1715    while ((!in_text_end || in_text < in_text_end) && *in_text)
     1716    {
     1717        unsigned int c = (unsigned int)(*in_text++);
     1718        if (c < 0x80)
     1719            bytes_count++;
     1720        else
     1721            bytes_count += ImTextCountUtf8BytesFromChar(c);
     1722    }
     1723    return bytes_count;
     1724}
     1725
     1726//-----------------------------------------------------------------------------
     1727// [SECTION] MISC HELPERS/UTILITIES (Color functions)
     1728// Note: The Convert functions are early design which are not consistent with other API.
     1729//-----------------------------------------------------------------------------
     1730
     1731IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)
     1732{
     1733    float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
     1734    int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
     1735    int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
     1736    int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
     1737    return IM_COL32(r, g, b, 0xFF);
    13351738}
    13361739
    13371740ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
    13381741{
    1339    float s = 1.0f / 255.0f;
    1340    return ImVec4(
    1341       ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
    1342       ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
    1343       ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
    1344       ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
     1742    float s = 1.0f / 255.0f;
     1743    return ImVec4(
     1744        ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
     1745        ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
     1746        ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
     1747        ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
    13451748}
    13461749
    13471750ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
    13481751{
    1349    ImU32 out;
    1350    out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
    1351    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
    1352    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
    1353    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
    1354    return out;
    1355 }
    1356 
    1357 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
    1358 {
    1359    ImGuiStyle& style = GImGui->Style;
    1360    ImVec4 c = style.Colors[idx];
    1361    c.w *= style.Alpha * alpha_mul;
    1362    return ColorConvertFloat4ToU32(c);
    1363 }
    1364 
    1365 ImU32 ImGui::GetColorU32(const ImVec4& col)
    1366 {
    1367    ImGuiStyle& style = GImGui->Style;
    1368    ImVec4 c = col;
    1369    c.w *= style.Alpha;
    1370    return ColorConvertFloat4ToU32(c);
    1371 }
    1372 
    1373 const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
    1374 {
    1375    ImGuiStyle& style = GImGui->Style;
    1376    return style.Colors[idx];
    1377 }
    1378 
    1379 ImU32 ImGui::GetColorU32(ImU32 col)
    1380 {
    1381    float style_alpha = GImGui->Style.Alpha;
    1382    if (style_alpha >= 1.0f)
    1383       return col;
    1384    ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
    1385    a = (ImU32)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
    1386    return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
     1752    ImU32 out;
     1753    out  = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
     1754    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
     1755    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
     1756    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
     1757    return out;
    13871758}
    13881759
     
    13911762void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
    13921763{
    1393    float K = 0.f;
    1394    if (g < b)
    1395    {
    1396       ImSwap(g, b);
    1397       K = -1.f;
    1398    }
    1399    if (r < g)
    1400    {
    1401       ImSwap(r, g);
    1402       K = -2.f / 6.f - K;
    1403    }
    1404 
    1405    const float chroma = r - (g < b ? g : b);
    1406    out_h = fabsf(K + (g - b) / (6.f * chroma + 1e-20f));
    1407    out_s = chroma / (r + 1e-20f);
    1408    out_v = r;
     1764    float K = 0.f;
     1765    if (g < b)
     1766    {
     1767        ImSwap(g, b);
     1768        K = -1.f;
     1769    }
     1770    if (r < g)
     1771    {
     1772        ImSwap(r, g);
     1773        K = -2.f / 6.f - K;
     1774    }
     1775
     1776    const float chroma = r - (g < b ? g : b);
     1777    out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
     1778    out_s = chroma / (r + 1e-20f);
     1779    out_v = r;
    14091780}
    14101781
     
    14131784void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
    14141785{
    1415    if (s == 0.0f)
    1416    {
    1417       // gray
    1418       out_r = out_g = out_b = v;
    1419       return;
    1420    }
    1421 
    1422    h = fmodf(h, 1.0f) / (60.0f / 360.0f);
    1423    int   i = (int)h;
    1424    float f = h - (float)i;
    1425    float p = v * (1.0f - s);
    1426    float q = v * (1.0f - s * f);
    1427    float t = v * (1.0f - s * (1.0f - f));
    1428 
    1429    switch (i)
    1430    {
    1431    case 0: out_r = v; out_g = t; out_b = p; break;
    1432    case 1: out_r = q; out_g = v; out_b = p; break;
    1433    case 2: out_r = p; out_g = v; out_b = t; break;
    1434    case 3: out_r = p; out_g = q; out_b = v; break;
    1435    case 4: out_r = t; out_g = p; out_b = v; break;
    1436    case 5: default: out_r = v; out_g = p; out_b = q; break;
    1437    }
    1438 }
    1439 
    1440 FILE* ImFileOpen(const char* filename, const char* mode)
    1441 {
    1442 #if defined(_WIN32) && !defined(__CYGWIN__)
    1443    // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can)
    1444    const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1;
    1445    const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
    1446    ImVector<ImWchar> buf;
    1447    buf.resize(filename_wsize + mode_wsize);
    1448    ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL);
    1449    ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL);
    1450    return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]);
    1451 #else
    1452    return fopen(filename, mode);
    1453 #endif
    1454 }
    1455 
    1456 // Load file content into memory
    1457 // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
    1458 void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes)
    1459 {
    1460    IM_ASSERT(filename && file_open_mode);
    1461    if (out_file_size)
    1462       *out_file_size = 0;
    1463 
    1464    FILE* f;
    1465    if ((f = ImFileOpen(filename, file_open_mode)) == NULL)
    1466       return NULL;
    1467 
    1468    long file_size_signed;
    1469    if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
    1470    {
    1471       fclose(f);
    1472       return NULL;
    1473    }
    1474 
    1475    int file_size = (int)file_size_signed;
    1476    void* file_data = ImGui::MemAlloc((size_t)(file_size + padding_bytes));
    1477    if (file_data == NULL)
    1478    {
    1479       fclose(f);
    1480       return NULL;
    1481    }
    1482    if (fread(file_data, 1, (size_t)file_size, f) != (size_t)file_size)
    1483    {
    1484       fclose(f);
    1485       ImGui::MemFree(file_data);
    1486       return NULL;
    1487    }
    1488    if (padding_bytes > 0)
    1489       memset((void *)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
    1490 
    1491    fclose(f);
    1492    if (out_file_size)
    1493       *out_file_size = file_size;
    1494 
    1495    return file_data;
     1786    if (s == 0.0f)
     1787    {
     1788        // gray
     1789        out_r = out_g = out_b = v;
     1790        return;
     1791    }
     1792
     1793    h = ImFmod(h, 1.0f) / (60.0f / 360.0f);
     1794    int   i = (int)h;
     1795    float f = h - (float)i;
     1796    float p = v * (1.0f - s);
     1797    float q = v * (1.0f - s * f);
     1798    float t = v * (1.0f - s * (1.0f - f));
     1799
     1800    switch (i)
     1801    {
     1802    case 0: out_r = v; out_g = t; out_b = p; break;
     1803    case 1: out_r = q; out_g = v; out_b = p; break;
     1804    case 2: out_r = p; out_g = v; out_b = t; break;
     1805    case 3: out_r = p; out_g = q; out_b = v; break;
     1806    case 4: out_r = t; out_g = p; out_b = v; break;
     1807    case 5: default: out_r = v; out_g = p; out_b = q; break;
     1808    }
    14961809}
    14971810
    14981811//-----------------------------------------------------------------------------
    1499 // ImGuiStorage
     1812// [SECTION] ImGuiStorage
    15001813// Helper: Key->value storage
    15011814//-----------------------------------------------------------------------------
    15021815
    15031816// std::lower_bound but without the bullshit
    1504 static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key)
    1505 {
    1506    ImVector<ImGuiStorage::Pair>::iterator first = data.begin();
    1507    ImVector<ImGuiStorage::Pair>::iterator last = data.end();
    1508    size_t count = (size_t)(last - first);
    1509    while (count > 0)
    1510    {
    1511       size_t count2 = count >> 1;
    1512       ImVector<ImGuiStorage::Pair>::iterator mid = first + count2;
    1513       if (mid->key < key)
    1514       {
    1515          first = ++mid;
    1516          count -= count2 + 1;
    1517       }
    1518       else
    1519       {
    1520          count = count2;
    1521       }
    1522    }
    1523    return first;
     1817static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)
     1818{
     1819    ImGuiStorage::ImGuiStoragePair* first = data.Data;
     1820    ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
     1821    size_t count = (size_t)(last - first);
     1822    while (count > 0)
     1823    {
     1824        size_t count2 = count >> 1;
     1825        ImGuiStorage::ImGuiStoragePair* mid = first + count2;
     1826        if (mid->key < key)
     1827        {
     1828            first = ++mid;
     1829            count -= count2 + 1;
     1830        }
     1831        else
     1832        {
     1833            count = count2;
     1834        }
     1835    }
     1836    return first;
    15241837}
    15251838
     
    15271840void ImGuiStorage::BuildSortByKey()
    15281841{
    1529    struct StaticFunc
    1530    {
    1531       static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
    1532       {
    1533          // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
    1534          if (((const Pair*)lhs)->key > ((const Pair*)rhs)->key) return +1;
    1535          if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1;
    1536          return 0;
    1537       }
    1538    };
    1539    if (Data.Size > 1)
    1540       qsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID);
     1842    struct StaticFunc
     1843    {
     1844        static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
     1845        {
     1846            // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
     1847            if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
     1848            if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
     1849            return 0;
     1850        }
     1851    };
     1852    if (Data.Size > 1)
     1853        ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID);
    15411854}
    15421855
    15431856int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
    15441857{
    1545    ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
    1546    if (it == Data.end() || it->key != key)
    1547       return default_val;
    1548    return it->val_i;
     1858    ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
     1859    if (it == Data.end() || it->key != key)
     1860        return default_val;
     1861    return it->val_i;
    15491862}
    15501863
    15511864bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
    15521865{
    1553    return GetInt(key, default_val ? 1 : 0) != 0;
     1866    return GetInt(key, default_val ? 1 : 0) != 0;
    15541867}
    15551868
    15561869float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
    15571870{
    1558    ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
    1559    if (it == Data.end() || it->key != key)
    1560       return default_val;
    1561    return it->val_f;
     1871    ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
     1872    if (it == Data.end() || it->key != key)
     1873        return default_val;
     1874    return it->val_f;
    15621875}
    15631876
    15641877void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
    15651878{
    1566    ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
    1567    if (it == Data.end() || it->key != key)
    1568       return NULL;
    1569    return it->val_p;
     1879    ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
     1880    if (it == Data.end() || it->key != key)
     1881        return NULL;
     1882    return it->val_p;
    15701883}
    15711884
     
    15731886int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
    15741887{
    1575    ImVector<Pair>::iterator it = LowerBound(Data, key);
    1576    if (it == Data.end() || it->key != key)
    1577       it = Data.insert(it, Pair(key, default_val));
    1578    return &it->val_i;
     1888    ImGuiStoragePair* it = LowerBound(Data, key);
     1889    if (it == Data.end() || it->key != key)
     1890        it = Data.insert(it, ImGuiStoragePair(key, default_val));
     1891    return &it->val_i;
    15791892}
    15801893
    15811894bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
    15821895{
    1583    return (bool*)GetIntRef(key, default_val ? 1 : 0);
     1896    return (bool*)GetIntRef(key, default_val ? 1 : 0);
    15841897}
    15851898
    15861899float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
    15871900{
    1588    ImVector<Pair>::iterator it = LowerBound(Data, key);
    1589    if (it == Data.end() || it->key != key)
    1590       it = Data.insert(it, Pair(key, default_val));
    1591    return &it->val_f;
     1901    ImGuiStoragePair* it = LowerBound(Data, key);
     1902    if (it == Data.end() || it->key != key)
     1903        it = Data.insert(it, ImGuiStoragePair(key, default_val));
     1904    return &it->val_f;
    15921905}
    15931906
    15941907void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
    15951908{
    1596    ImVector<Pair>::iterator it = LowerBound(Data, key);
    1597    if (it == Data.end() || it->key != key)
    1598       it = Data.insert(it, Pair(key, default_val));
    1599    return &it->val_p;
     1909    ImGuiStoragePair* it = LowerBound(Data, key);
     1910    if (it == Data.end() || it->key != key)
     1911        it = Data.insert(it, ImGuiStoragePair(key, default_val));
     1912    return &it->val_p;
    16001913}
    16011914
     
    16031916void ImGuiStorage::SetInt(ImGuiID key, int val)
    16041917{
    1605    ImVector<Pair>::iterator it = LowerBound(Data, key);
    1606    if (it == Data.end() || it->key != key)
    1607    {
    1608       Data.insert(it, Pair(key, val));
    1609       return;
    1610    }
    1611    it->val_i = val;
     1918    ImGuiStoragePair* it = LowerBound(Data, key);
     1919    if (it == Data.end() || it->key != key)
     1920    {
     1921        Data.insert(it, ImGuiStoragePair(key, val));
     1922        return;
     1923    }
     1924    it->val_i = val;
    16121925}
    16131926
    16141927void ImGuiStorage::SetBool(ImGuiID key, bool val)
    16151928{
    1616    SetInt(key, val ? 1 : 0);
     1929    SetInt(key, val ? 1 : 0);
    16171930}
    16181931
    16191932void ImGuiStorage::SetFloat(ImGuiID key, float val)
    16201933{
    1621    ImVector<Pair>::iterator it = LowerBound(Data, key);
    1622    if (it == Data.end() || it->key != key)
    1623    {
    1624       Data.insert(it, Pair(key, val));
    1625       return;
    1626    }
    1627    it->val_f = val;
     1934    ImGuiStoragePair* it = LowerBound(Data, key);
     1935    if (it == Data.end() || it->key != key)
     1936    {
     1937        Data.insert(it, ImGuiStoragePair(key, val));
     1938        return;
     1939    }
     1940    it->val_f = val;
    16281941}
    16291942
    16301943void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
    16311944{
    1632    ImVector<Pair>::iterator it = LowerBound(Data, key);
    1633    if (it == Data.end() || it->key != key)
    1634    {
    1635       Data.insert(it, Pair(key, val));
    1636       return;
    1637    }
    1638    it->val_p = val;
     1945    ImGuiStoragePair* it = LowerBound(Data, key);
     1946    if (it == Data.end() || it->key != key)
     1947    {
     1948        Data.insert(it, ImGuiStoragePair(key, val));
     1949        return;
     1950    }
     1951    it->val_p = val;
    16391952}
    16401953
    16411954void ImGuiStorage::SetAllInt(int v)
    16421955{
    1643    for (int i = 0; i < Data.Size; i++)
    1644       Data[i].val_i = v;
     1956    for (int i = 0; i < Data.Size; i++)
     1957        Data[i].val_i = v;
    16451958}
    16461959
    16471960//-----------------------------------------------------------------------------
    1648 // ImGuiTextFilter
     1961// [SECTION] ImGuiTextFilter
    16491962//-----------------------------------------------------------------------------
    16501963
     
    16521965ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
    16531966{
    1654    if (default_filter)
    1655    {
    1656       ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
    1657       Build();
    1658    }
    1659    else
    1660    {
    1661       InputBuf[0] = 0;
    1662       CountGrep = 0;
    1663    }
     1967    if (default_filter)
     1968    {
     1969        ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
     1970        Build();
     1971    }
     1972    else
     1973    {
     1974        InputBuf[0] = 0;
     1975        CountGrep = 0;
     1976    }
    16641977}
    16651978
    16661979bool ImGuiTextFilter::Draw(const char* label, float width)
    16671980{
    1668    if (width != 0.0f)
    1669       ImGui::PushItemWidth(width);
    1670    bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
    1671    if (width != 0.0f)
    1672       ImGui::PopItemWidth();
    1673    if (value_changed)
    1674       Build();
    1675    return value_changed;
    1676 }
    1677 
    1678 void ImGuiTextFilter::TextRange::split(char separator, ImVector<TextRange>& out)
    1679 {
    1680    out.resize(0);
    1681    const char* wb = b;
    1682    const char* we = wb;
    1683    while (we < e)
    1684    {
    1685       if (*we == separator)
    1686       {
    1687          out.push_back(TextRange(wb, we));
    1688          wb = we + 1;
    1689       }
    1690       we++;
    1691    }
    1692    if (wb != we)
    1693       out.push_back(TextRange(wb, we));
     1981    if (width != 0.0f)
     1982        ImGui::SetNextItemWidth(width);
     1983    bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
     1984    if (value_changed)
     1985        Build();
     1986    return value_changed;
     1987}
     1988
     1989void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
     1990{
     1991    out->resize(0);
     1992    const char* wb = b;
     1993    const char* we = wb;
     1994    while (we < e)
     1995    {
     1996        if (*we == separator)
     1997        {
     1998            out->push_back(ImGuiTextRange(wb, we));
     1999            wb = we + 1;
     2000        }
     2001        we++;
     2002    }
     2003    if (wb != we)
     2004        out->push_back(ImGuiTextRange(wb, we));
    16942005}
    16952006
    16962007void ImGuiTextFilter::Build()
    16972008{
    1698    Filters.resize(0);
    1699    TextRange input_range(InputBuf, InputBuf + strlen(InputBuf));
    1700    input_range.split(',', Filters);
    1701 
    1702    CountGrep = 0;
    1703    for (int i = 0; i != Filters.Size; i++)
    1704    {
    1705       Filters[i].trim_blanks();
    1706       if (Filters[i].empty())
    1707          continue;
    1708       if (Filters[i].front() != '-')
    1709          CountGrep += 1;
    1710    }
     2009    Filters.resize(0);
     2010    ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf));
     2011    input_range.split(',', &Filters);
     2012
     2013    CountGrep = 0;
     2014    for (int i = 0; i != Filters.Size; i++)
     2015    {
     2016        ImGuiTextRange& f = Filters[i];
     2017        while (f.b < f.e && ImCharIsBlankA(f.b[0]))
     2018            f.b++;
     2019        while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
     2020            f.e--;
     2021        if (f.empty())
     2022            continue;
     2023        if (Filters[i].b[0] != '-')
     2024            CountGrep += 1;
     2025    }
    17112026}
    17122027
    17132028bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
    17142029{
    1715    if (Filters.empty())
    1716       return true;
    1717 
    1718    if (text == NULL)
    1719       text = "";
    1720 
    1721    for (int i = 0; i != Filters.Size; i++)
    1722    {
    1723       const TextRange& f = Filters[i];
    1724       if (f.empty())
    1725          continue;
    1726       if (f.front() == '-')
    1727       {
    1728          // Subtract
    1729          if (ImStristr(text, text_end, f.begin() + 1, f.end()) != NULL)
    1730             return false;
    1731       }
    1732       else
    1733       {
    1734          // Grep
    1735          if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)
    1736             return true;
    1737       }
    1738    }
    1739 
    1740    // Implicit * grep
    1741    if (CountGrep == 0)
    1742       return true;
    1743 
    1744    return false;
     2030    if (Filters.empty())
     2031        return true;
     2032
     2033    if (text == NULL)
     2034        text = "";
     2035
     2036    for (int i = 0; i != Filters.Size; i++)
     2037    {
     2038        const ImGuiTextRange& f = Filters[i];
     2039        if (f.empty())
     2040            continue;
     2041        if (f.b[0] == '-')
     2042        {
     2043            // Subtract
     2044            if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
     2045                return false;
     2046        }
     2047        else
     2048        {
     2049            // Grep
     2050            if (ImStristr(text, text_end, f.b, f.e) != NULL)
     2051                return true;
     2052        }
     2053    }
     2054
     2055    // Implicit * grep
     2056    if (CountGrep == 0)
     2057        return true;
     2058
     2059    return false;
    17452060}
    17462061
    17472062//-----------------------------------------------------------------------------
    1748 // ImGuiTextBuffer
     2063// [SECTION] ImGuiTextBuffer
    17492064//-----------------------------------------------------------------------------
    17502065
     
    17522067// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
    17532068#ifndef va_copy
     2069#if defined(__GNUC__) || defined(__clang__)
     2070#define va_copy(dest, src) __builtin_va_copy(dest, src)
     2071#else
    17542072#define va_copy(dest, src) (dest = src)
    17552073#endif
     2074#endif
     2075
     2076char ImGuiTextBuffer::EmptyString[1] = { 0 };
     2077
     2078void ImGuiTextBuffer::append(const char* str, const char* str_end)
     2079{
     2080    int len = str_end ? (int)(str_end - str) : (int)strlen(str);
     2081
     2082    // Add zero-terminator the first time
     2083    const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
     2084    const int needed_sz = write_off + len;
     2085    if (write_off + len >= Buf.Capacity)
     2086    {
     2087        int new_capacity = Buf.Capacity * 2;
     2088        Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
     2089    }
     2090
     2091    Buf.resize(needed_sz);
     2092    memcpy(&Buf[write_off - 1], str, (size_t)len);
     2093    Buf[write_off - 1 + len] = 0;
     2094}
     2095
     2096void ImGuiTextBuffer::appendf(const char* fmt, ...)
     2097{
     2098    va_list args;
     2099    va_start(args, fmt);
     2100    appendfv(fmt, args);
     2101    va_end(args);
     2102}
    17562103
    17572104// Helper: Text buffer for logging/accumulating text
    17582105void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
    17592106{
    1760    va_list args_copy;
    1761    va_copy(args_copy, args);
    1762 
    1763    int len = ImFormatStringV(NULL, 0, fmt, args);         // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
    1764    if (len <= 0)
    1765    {
    1766       va_end(args_copy);
    1767       return;
    1768    }
    1769 
    1770    const int write_off = Buf.Size;
    1771    const int needed_sz = write_off + len;
    1772    if (write_off + len >= Buf.Capacity)
    1773    {
    1774       int double_capacity = Buf.Capacity * 2;
    1775       Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity);
    1776    }
    1777 
    1778    Buf.resize(needed_sz);
    1779    ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
    1780    va_end(args_copy);
    1781 }
    1782 
    1783 void ImGuiTextBuffer::appendf(const char* fmt, ...)
    1784 {
    1785    va_list args;
    1786    va_start(args, fmt);
    1787    appendfv(fmt, args);
    1788    va_end(args);
     2107    va_list args_copy;
     2108    va_copy(args_copy, args);
     2109
     2110    int len = ImFormatStringV(NULL, 0, fmt, args);         // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
     2111    if (len <= 0)
     2112    {
     2113        va_end(args_copy);
     2114        return;
     2115    }
     2116
     2117    // Add zero-terminator the first time
     2118    const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
     2119    const int needed_sz = write_off + len;
     2120    if (write_off + len >= Buf.Capacity)
     2121    {
     2122        int new_capacity = Buf.Capacity * 2;
     2123        Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
     2124    }
     2125
     2126    Buf.resize(needed_sz);
     2127    ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
     2128    va_end(args_copy);
    17892129}
    17902130
    17912131//-----------------------------------------------------------------------------
    1792 // ImGuiSimpleColumns (internal use only)
     2132// [SECTION] ImGuiListClipper
     2133// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed
     2134// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO)
    17932135//-----------------------------------------------------------------------------
    17942136
    1795 ImGuiMenuColumns::ImGuiMenuColumns()
    1796 {
    1797    Count = 0;
    1798    Spacing = Width = NextWidth = 0.0f;
    1799    memset(Pos, 0, sizeof(Pos));
    1800    memset(NextWidths, 0, sizeof(NextWidths));
    1801 }
    1802 
    1803 void ImGuiMenuColumns::Update(int count, float spacing, bool clear)
    1804 {
    1805    IM_ASSERT(Count <= IM_ARRAYSIZE(Pos));
    1806    Count = count;
    1807    Width = NextWidth = 0.0f;
    1808    Spacing = spacing;
    1809    if (clear) memset(NextWidths, 0, sizeof(NextWidths));
    1810    for (int i = 0; i < Count; i++)
    1811    {
    1812       if (i > 0 && NextWidths[i] > 0.0f)
    1813          Width += Spacing;
    1814       Pos[i] = (float)(int)Width;
    1815       Width += NextWidths[i];
    1816       NextWidths[i] = 0.0f;
    1817    }
    1818 }
    1819 
    1820 float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double
    1821 {
    1822    NextWidth = 0.0f;
    1823    NextWidths[0] = ImMax(NextWidths[0], w0);
    1824    NextWidths[1] = ImMax(NextWidths[1], w1);
    1825    NextWidths[2] = ImMax(NextWidths[2], w2);
    1826    for (int i = 0; i < 3; i++)
    1827       NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f);
    1828    return ImMax(Width, NextWidth);
    1829 }
    1830 
    1831 float ImGuiMenuColumns::CalcExtraSpace(float avail_w)
    1832 {
    1833    return ImMax(0.0f, avail_w - Width);
    1834 }
    1835 
    1836 //-----------------------------------------------------------------------------
    1837 // ImGuiListClipper
    1838 //-----------------------------------------------------------------------------
    1839 
    1840 static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
    1841 {
    1842    // Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor.
    1843    // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
    1844    // The clipper should probably have a 4th step to display the last item in a regular manner.
    1845    ImGui::SetCursorPosY(pos_y);
    1846    ImGuiWindow* window = ImGui::GetCurrentWindow();
    1847    window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height;      // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
    1848    window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y);    // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
    1849    if (window->DC.ColumnsSet)
    1850       window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y;           // Setting this so that cell Y position are set properly
    1851 }
    1852 
    1853 // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
     2137// Helper to calculate coarse clipping of large list of evenly sized items.
     2138// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
     2139// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
     2140void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
     2141{
     2142    ImGuiContext& g = *GImGui;
     2143    ImGuiWindow* window = g.CurrentWindow;
     2144    if (g.LogEnabled)
     2145    {
     2146        // If logging is active, do not perform any clipping
     2147        *out_items_display_start = 0;
     2148        *out_items_display_end = items_count;
     2149        return;
     2150    }
     2151    if (window->SkipItems)
     2152    {
     2153        *out_items_display_start = *out_items_display_end = 0;
     2154        return;
     2155    }
     2156
     2157    // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
     2158    ImRect unclipped_rect = window->ClipRect;
     2159    if (g.NavMoveRequest)
     2160        unclipped_rect.Add(g.NavScoringRect);
     2161    if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
     2162        unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max));
     2163
     2164    const ImVec2 pos = window->DC.CursorPos;
     2165    int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
     2166    int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
     2167
     2168    // When performing a navigation request, ensure we have one item extra in the direction we are moving to
     2169    if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
     2170        start--;
     2171    if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
     2172        end++;
     2173
     2174    start = ImClamp(start, 0, items_count);
     2175    end = ImClamp(end + 1, start, items_count);
     2176    *out_items_display_start = start;
     2177    *out_items_display_end = end;
     2178}
     2179
     2180static void SetCursorPosYAndSetupForPrevLine(float pos_y, float line_height)
     2181{
     2182    // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
     2183    // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
     2184    // The clipper should probably have a 4th step to display the last item in a regular manner.
     2185    ImGuiContext& g = *GImGui;
     2186    ImGuiWindow* window = g.CurrentWindow;
     2187    window->DC.CursorPos.y = pos_y;
     2188    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y);
     2189    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.
     2190    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.
     2191    if (ImGuiColumns* columns = window->DC.CurrentColumns)
     2192        columns->LineMinY = window->DC.CursorPos.y;                         // Setting this so that cell Y position are set properly
     2193}
     2194
     2195ImGuiListClipper::ImGuiListClipper()
     2196{
     2197    memset(this, 0, sizeof(*this));
     2198    ItemsCount = -1;
     2199}
     2200
     2201ImGuiListClipper::~ImGuiListClipper()
     2202{
     2203    IM_ASSERT(ItemsCount == -1 && "Forgot to call End(), or to Step() until false?");
     2204}
     2205
     2206// Use case A: Begin() called from constructor with items_height<0, then called again from Step() in StepNo 1
    18542207// Use case B: Begin() called from constructor with items_height>0
    18552208// 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.
    1856 void ImGuiListClipper::Begin(int count, float items_height)
    1857 {
    1858    StartPosY = ImGui::GetCursorPosY();
    1859    ItemsHeight = items_height;
    1860    ItemsCount = count;
    1861    StepNo = 0;
    1862    DisplayEnd = DisplayStart = -1;
    1863    if (ItemsHeight > 0.0f)
    1864    {
    1865       ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
    1866       if (DisplayStart > 0)
    1867          SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
    1868       StepNo = 2;
    1869    }
     2209void ImGuiListClipper::Begin(int items_count, float items_height)
     2210{
     2211    ImGuiContext& g = *GImGui;
     2212    ImGuiWindow* window = g.CurrentWindow;
     2213
     2214    StartPosY = window->DC.CursorPos.y;
     2215    ItemsHeight = items_height;
     2216    ItemsCount = items_count;
     2217    StepNo = 0;
     2218    DisplayStart = -1;
     2219    DisplayEnd = 0;
    18702220}
    18712221
    18722222void ImGuiListClipper::End()
    18732223{
    1874    if (ItemsCount < 0)
    1875       return;
    1876    // 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.
    1877    if (ItemsCount < INT_MAX)
    1878       SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
    1879    ItemsCount = -1;
    1880    StepNo = 3;
     2224    if (ItemsCount < 0) // Already ended
     2225        return;
     2226
     2227    // 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.
     2228    if (ItemsCount < INT_MAX && DisplayStart >= 0)
     2229        SetCursorPosYAndSetupForPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight);
     2230    ItemsCount = -1;
     2231    StepNo = 3;
    18812232}
    18822233
    18832234bool ImGuiListClipper::Step()
    18842235{
    1885    if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
    1886    {
    1887       ItemsCount = -1;
    1888       return false;
    1889    }
    1890    if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height.
    1891    {
    1892       DisplayStart = 0;
    1893       DisplayEnd = 1;
    1894       StartPosY = ImGui::GetCursorPosY();
    1895       StepNo = 1;
    1896       return true;
    1897    }
    1898    if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element.
    1899    {
    1900       if (ItemsCount == 1) { ItemsCount = -1; return false; }
    1901       float items_height = ImGui::GetCursorPosY() - StartPosY;
    1902       IM_ASSERT(items_height > 0.0f);   // If this triggers, it means Item 0 hasn't moved the cursor vertically
    1903       Begin(ItemsCount - 1, items_height);
    1904       DisplayStart++;
    1905       DisplayEnd++;
    1906       StepNo = 3;
    1907       return true;
    1908    }
    1909    if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3.
    1910    {
    1911       IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
    1912       StepNo = 3;
    1913       return true;
    1914    }
    1915    if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop.
    1916       End();
    1917    return false;
     2236    ImGuiContext& g = *GImGui;
     2237    ImGuiWindow* window = g.CurrentWindow;
     2238
     2239    // Reached end of list
     2240    if (DisplayEnd >= ItemsCount || window->SkipItems)
     2241    {
     2242        End();
     2243        return false;
     2244    }
     2245
     2246    // Step 0: Let you process the first element (regardless of it being visible or not, so we can measure the element height)
     2247    if (StepNo == 0)
     2248    {
     2249        StartPosY = window->DC.CursorPos.y;
     2250        if (ItemsHeight <= 0.0f)
     2251        {
     2252            // Submit the first item so we can measure its height (generally it is 0..1)
     2253            DisplayStart = 0;
     2254            DisplayEnd = 1;
     2255            StepNo = 1;
     2256            return true;
     2257        }
     2258
     2259        // Already has item height (given by user in Begin): skip to calculating step
     2260        DisplayStart = DisplayEnd;
     2261        StepNo = 2;
     2262    }
     2263
     2264    // Step 1: the clipper infer height from first element
     2265    if (StepNo == 1)
     2266    {
     2267        IM_ASSERT(ItemsHeight <= 0.0f);
     2268        ItemsHeight = window->DC.CursorPos.y - StartPosY;
     2269        IM_ASSERT(ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
     2270        StepNo = 2;
     2271    }
     2272
     2273    // Step 2: calculate the actual range of elements to display, and position the cursor before the first element
     2274    if (StepNo == 2)
     2275    {
     2276        IM_ASSERT(ItemsHeight > 0.0f);
     2277
     2278        int already_submitted = DisplayEnd;
     2279        ImGui::CalcListClipping(ItemsCount - already_submitted, ItemsHeight, &DisplayStart, &DisplayEnd);
     2280        DisplayStart += already_submitted;
     2281        DisplayEnd += already_submitted;
     2282
     2283        // Seek cursor
     2284        if (DisplayStart > already_submitted)
     2285            SetCursorPosYAndSetupForPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight);
     2286
     2287        StepNo = 3;
     2288        return true;
     2289    }
     2290
     2291    // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
     2292    // Advance the cursor to the end of the list and then returns 'false' to end the loop.
     2293    if (StepNo == 3)
     2294    {
     2295        // Seek cursor
     2296        if (ItemsCount < INT_MAX)
     2297            SetCursorPosYAndSetupForPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
     2298        ItemsCount = -1;
     2299        return false;
     2300    }
     2301
     2302    IM_ASSERT(0);
     2303    return false;
    19182304}
    19192305
    19202306//-----------------------------------------------------------------------------
    1921 // ImGuiWindow
     2307// [SECTION] STYLING
    19222308//-----------------------------------------------------------------------------
    19232309
     2310ImGuiStyle& ImGui::GetStyle()
     2311{
     2312    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
     2313    return GImGui->Style;
     2314}
     2315
     2316ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
     2317{
     2318    ImGuiStyle& style = GImGui->Style;
     2319    ImVec4 c = style.Colors[idx];
     2320    c.w *= style.Alpha * alpha_mul;
     2321    return ColorConvertFloat4ToU32(c);
     2322}
     2323
     2324ImU32 ImGui::GetColorU32(const ImVec4& col)
     2325{
     2326    ImGuiStyle& style = GImGui->Style;
     2327    ImVec4 c = col;
     2328    c.w *= style.Alpha;
     2329    return ColorConvertFloat4ToU32(c);
     2330}
     2331
     2332const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
     2333{
     2334    ImGuiStyle& style = GImGui->Style;
     2335    return style.Colors[idx];
     2336}
     2337
     2338ImU32 ImGui::GetColorU32(ImU32 col)
     2339{
     2340    ImGuiStyle& style = GImGui->Style;
     2341    if (style.Alpha >= 1.0f)
     2342        return col;
     2343    ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
     2344    a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
     2345    return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
     2346}
     2347
     2348// 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
     2349void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)
     2350{
     2351    ImGuiContext& g = *GImGui;
     2352    ImGuiColorMod backup;
     2353    backup.Col = idx;
     2354    backup.BackupValue = g.Style.Colors[idx];
     2355    g.ColorModifiers.push_back(backup);
     2356    g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
     2357}
     2358
     2359void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
     2360{
     2361    ImGuiContext& g = *GImGui;
     2362    ImGuiColorMod backup;
     2363    backup.Col = idx;
     2364    backup.BackupValue = g.Style.Colors[idx];
     2365    g.ColorModifiers.push_back(backup);
     2366    g.Style.Colors[idx] = col;
     2367}
     2368
     2369void ImGui::PopStyleColor(int count)
     2370{
     2371    ImGuiContext& g = *GImGui;
     2372    while (count > 0)
     2373    {
     2374        ImGuiColorMod& backup = g.ColorModifiers.back();
     2375        g.Style.Colors[backup.Col] = backup.BackupValue;
     2376        g.ColorModifiers.pop_back();
     2377        count--;
     2378    }
     2379}
     2380
     2381struct ImGuiStyleVarInfo
     2382{
     2383    ImGuiDataType   Type;
     2384    ImU32           Count;
     2385    ImU32           Offset;
     2386    void*           GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
     2387};
     2388
     2389static const ImGuiStyleVarInfo GStyleVarInfo[] =
     2390{
     2391    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) },               // ImGuiStyleVar_Alpha
     2392    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) },       // ImGuiStyleVar_WindowPadding
     2393    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) },      // ImGuiStyleVar_WindowRounding
     2394    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) },    // ImGuiStyleVar_WindowBorderSize
     2395    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) },       // ImGuiStyleVar_WindowMinSize
     2396    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) },    // ImGuiStyleVar_WindowTitleAlign
     2397    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) },       // ImGuiStyleVar_ChildRounding
     2398    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) },     // ImGuiStyleVar_ChildBorderSize
     2399    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) },       // ImGuiStyleVar_PopupRounding
     2400    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) },     // ImGuiStyleVar_PopupBorderSize
     2401    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) },        // ImGuiStyleVar_FramePadding
     2402    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) },       // ImGuiStyleVar_FrameRounding
     2403    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) },     // ImGuiStyleVar_FrameBorderSize
     2404    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) },         // ImGuiStyleVar_ItemSpacing
     2405    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) },    // ImGuiStyleVar_ItemInnerSpacing
     2406    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },       // ImGuiStyleVar_IndentSpacing
     2407    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) },       // ImGuiStyleVar_ScrollbarSize
     2408    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) },   // ImGuiStyleVar_ScrollbarRounding
     2409    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },         // ImGuiStyleVar_GrabMinSize
     2410    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) },        // ImGuiStyleVar_GrabRounding
     2411    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) },         // ImGuiStyleVar_TabRounding
     2412    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },     // ImGuiStyleVar_ButtonTextAlign
     2413    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
     2414};
     2415
     2416static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
     2417{
     2418    IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
     2419    IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
     2420    return &GStyleVarInfo[idx];
     2421}
     2422
     2423void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
     2424{
     2425    const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
     2426    if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
     2427    {
     2428        ImGuiContext& g = *GImGui;
     2429        float* pvar = (float*)var_info->GetVarPtr(&g.Style);
     2430        g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
     2431        *pvar = val;
     2432        return;
     2433    }
     2434    IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");
     2435}
     2436
     2437void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
     2438{
     2439    const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
     2440    if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
     2441    {
     2442        ImGuiContext& g = *GImGui;
     2443        ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
     2444        g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
     2445        *pvar = val;
     2446        return;
     2447    }
     2448    IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");
     2449}
     2450
     2451void ImGui::PopStyleVar(int count)
     2452{
     2453    ImGuiContext& g = *GImGui;
     2454    while (count > 0)
     2455    {
     2456        // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
     2457        ImGuiStyleMod& backup = g.StyleModifiers.back();
     2458        const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
     2459        void* data = info->GetVarPtr(&g.Style);
     2460        if (info->Type == ImGuiDataType_Float && info->Count == 1)      { ((float*)data)[0] = backup.BackupFloat[0]; }
     2461        else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
     2462        g.StyleModifiers.pop_back();
     2463        count--;
     2464    }
     2465}
     2466
     2467const char* ImGui::GetStyleColorName(ImGuiCol idx)
     2468{
     2469    // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
     2470    switch (idx)
     2471    {
     2472    case ImGuiCol_Text: return "Text";
     2473    case ImGuiCol_TextDisabled: return "TextDisabled";
     2474    case ImGuiCol_WindowBg: return "WindowBg";
     2475    case ImGuiCol_ChildBg: return "ChildBg";
     2476    case ImGuiCol_PopupBg: return "PopupBg";
     2477    case ImGuiCol_Border: return "Border";
     2478    case ImGuiCol_BorderShadow: return "BorderShadow";
     2479    case ImGuiCol_FrameBg: return "FrameBg";
     2480    case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
     2481    case ImGuiCol_FrameBgActive: return "FrameBgActive";
     2482    case ImGuiCol_TitleBg: return "TitleBg";
     2483    case ImGuiCol_TitleBgActive: return "TitleBgActive";
     2484    case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
     2485    case ImGuiCol_MenuBarBg: return "MenuBarBg";
     2486    case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
     2487    case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
     2488    case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
     2489    case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
     2490    case ImGuiCol_CheckMark: return "CheckMark";
     2491    case ImGuiCol_SliderGrab: return "SliderGrab";
     2492    case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
     2493    case ImGuiCol_Button: return "Button";
     2494    case ImGuiCol_ButtonHovered: return "ButtonHovered";
     2495    case ImGuiCol_ButtonActive: return "ButtonActive";
     2496    case ImGuiCol_Header: return "Header";
     2497    case ImGuiCol_HeaderHovered: return "HeaderHovered";
     2498    case ImGuiCol_HeaderActive: return "HeaderActive";
     2499    case ImGuiCol_Separator: return "Separator";
     2500    case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
     2501    case ImGuiCol_SeparatorActive: return "SeparatorActive";
     2502    case ImGuiCol_ResizeGrip: return "ResizeGrip";
     2503    case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
     2504    case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
     2505    case ImGuiCol_Tab: return "Tab";
     2506    case ImGuiCol_TabHovered: return "TabHovered";
     2507    case ImGuiCol_TabActive: return "TabActive";
     2508    case ImGuiCol_TabUnfocused: return "TabUnfocused";
     2509    case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
     2510    case ImGuiCol_PlotLines: return "PlotLines";
     2511    case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
     2512    case ImGuiCol_PlotHistogram: return "PlotHistogram";
     2513    case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
     2514    case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
     2515    case ImGuiCol_DragDropTarget: return "DragDropTarget";
     2516    case ImGuiCol_NavHighlight: return "NavHighlight";
     2517    case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
     2518    case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
     2519    case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
     2520    }
     2521    IM_ASSERT(0);
     2522    return "Unknown";
     2523}
     2524
     2525
     2526//-----------------------------------------------------------------------------
     2527// [SECTION] RENDER HELPERS
     2528// Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change,
     2529// we need a nicer separation between low-level functions and high-level functions relying on the ImGui context.
     2530// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context.
     2531//-----------------------------------------------------------------------------
     2532
     2533const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
     2534{
     2535    const char* text_display_end = text;
     2536    if (!text_end)
     2537        text_end = (const char*)-1;
     2538
     2539    while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
     2540        text_display_end++;
     2541    return text_display_end;
     2542}
     2543
     2544// Internal ImGui functions to render text
     2545// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
     2546void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
     2547{
     2548    ImGuiContext& g = *GImGui;
     2549    ImGuiWindow* window = g.CurrentWindow;
     2550
     2551    // Hide anything after a '##' string
     2552    const char* text_display_end;
     2553    if (hide_text_after_hash)
     2554    {
     2555        text_display_end = FindRenderedTextEnd(text, text_end);
     2556    }
     2557    else
     2558    {
     2559        if (!text_end)
     2560            text_end = text + strlen(text); // FIXME-OPT
     2561        text_display_end = text_end;
     2562    }
     2563
     2564    if (text != text_display_end)
     2565    {
     2566        window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
     2567        if (g.LogEnabled)
     2568            LogRenderedText(&pos, text, text_display_end);
     2569    }
     2570}
     2571
     2572void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
     2573{
     2574    ImGuiContext& g = *GImGui;
     2575    ImGuiWindow* window = g.CurrentWindow;
     2576
     2577    if (!text_end)
     2578        text_end = text + strlen(text); // FIXME-OPT
     2579
     2580    if (text != text_end)
     2581    {
     2582        window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
     2583        if (g.LogEnabled)
     2584            LogRenderedText(&pos, text, text_end);
     2585    }
     2586}
     2587
     2588// Default clip_rect uses (pos_min,pos_max)
     2589// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
     2590void 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)
     2591{
     2592    // Perform CPU side clipping for single clipped element to avoid using scissor state
     2593    ImVec2 pos = pos_min;
     2594    const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
     2595
     2596    const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
     2597    const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
     2598    bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
     2599    if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
     2600        need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
     2601
     2602    // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
     2603    if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
     2604    if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
     2605
     2606    // Render
     2607    if (need_clipping)
     2608    {
     2609        ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
     2610        draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
     2611    }
     2612    else
     2613    {
     2614        draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
     2615    }
     2616}
     2617
     2618void 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)
     2619{
     2620    // Hide anything after a '##' string
     2621    const char* text_display_end = FindRenderedTextEnd(text, text_end);
     2622    const int text_len = (int)(text_display_end - text);
     2623    if (text_len == 0)
     2624        return;
     2625
     2626    ImGuiContext& g = *GImGui;
     2627    ImGuiWindow* window = g.CurrentWindow;
     2628    RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
     2629    if (g.LogEnabled)
     2630        LogRenderedText(&pos_min, text, text_display_end);
     2631}
     2632
     2633
     2634// Another overly complex function until we reorganize everything into a nice all-in-one helper.
     2635// 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.
     2636// 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.
     2637void 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)
     2638{
     2639    ImGuiContext& g = *GImGui;
     2640    if (text_end_full == NULL)
     2641        text_end_full = FindRenderedTextEnd(text);
     2642    const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
     2643
     2644    //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));
     2645    //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));
     2646    //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));
     2647    // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
     2648    if (text_size.x > pos_max.x - pos_min.x)
     2649    {
     2650        // Hello wo...
     2651        // |       |   |
     2652        // min   max   ellipsis_max
     2653        //          <-> this is generally some padding value
     2654
     2655        const ImFont* font = draw_list->_Data->Font;
     2656        const float font_size = draw_list->_Data->FontSize;
     2657        const char* text_end_ellipsis = NULL;
     2658
     2659        ImWchar ellipsis_char = font->EllipsisChar;
     2660        int ellipsis_char_count = 1;
     2661        if (ellipsis_char == (ImWchar)-1)
     2662        {
     2663            ellipsis_char = (ImWchar)'.';
     2664            ellipsis_char_count = 3;
     2665        }
     2666        const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
     2667
     2668        float ellipsis_glyph_width = glyph->X1;                 // Width of the glyph with no padding on either side
     2669        float ellipsis_total_width = ellipsis_glyph_width;      // Full width of entire ellipsis
     2670
     2671        if (ellipsis_char_count > 1)
     2672        {
     2673            // Full ellipsis size without free spacing after it.
     2674            const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize);
     2675            ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
     2676            ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
     2677        }
     2678
     2679        // We can now claim the space between pos_max.x and ellipsis_max.x
     2680        const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f);
     2681        float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
     2682        if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
     2683        {
     2684            // Always display at least 1 character if there's no room for character + ellipsis
     2685            text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
     2686            text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
     2687        }
     2688        while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
     2689        {
     2690            // 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)
     2691            text_end_ellipsis--;
     2692            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
     2693        }
     2694
     2695        // Render text, render ellipsis
     2696        RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
     2697        float ellipsis_x = pos_min.x + text_size_clipped_x;
     2698        if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x)
     2699            for (int i = 0; i < ellipsis_char_count; i++)
     2700            {
     2701                font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char);
     2702                ellipsis_x += ellipsis_glyph_width;
     2703            }
     2704    }
     2705    else
     2706    {
     2707        RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
     2708    }
     2709
     2710    if (g.LogEnabled)
     2711        LogRenderedText(&pos_min, text, text_end_full);
     2712}
     2713
     2714// Render a rectangle shaped with optional rounding and borders
     2715void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
     2716{
     2717    ImGuiContext& g = *GImGui;
     2718    ImGuiWindow* window = g.CurrentWindow;
     2719    window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
     2720    const float border_size = g.Style.FrameBorderSize;
     2721    if (border && border_size > 0.0f)
     2722    {
     2723        window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
     2724        window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
     2725    }
     2726}
     2727
     2728void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
     2729{
     2730    ImGuiContext& g = *GImGui;
     2731    ImGuiWindow* window = g.CurrentWindow;
     2732    const float border_size = g.Style.FrameBorderSize;
     2733    if (border_size > 0.0f)
     2734    {
     2735        window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
     2736        window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
     2737    }
     2738}
     2739
     2740void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)
     2741{
     2742    ImGuiContext& g = *GImGui;
     2743    if (id != g.NavId)
     2744        return;
     2745    if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
     2746        return;
     2747    ImGuiWindow* window = g.CurrentWindow;
     2748    if (window->DC.NavHideHighlightOneFrame)
     2749        return;
     2750
     2751    float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
     2752    ImRect display_rect = bb;
     2753    display_rect.ClipWith(window->ClipRect);
     2754    if (flags & ImGuiNavHighlightFlags_TypeDefault)
     2755    {
     2756        const float THICKNESS = 2.0f;
     2757        const float DISTANCE = 3.0f + THICKNESS * 0.5f;
     2758        display_rect.Expand(ImVec2(DISTANCE, DISTANCE));
     2759        bool fully_visible = window->ClipRect.Contains(display_rect);
     2760        if (!fully_visible)
     2761            window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
     2762        window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), display_rect.Max - ImVec2(THICKNESS * 0.5f, THICKNESS * 0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS);
     2763        if (!fully_visible)
     2764            window->DrawList->PopClipRect();
     2765    }
     2766    if (flags & ImGuiNavHighlightFlags_TypeThin)
     2767    {
     2768        window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f);
     2769    }
     2770}
     2771
     2772//-----------------------------------------------------------------------------
     2773// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
     2774//-----------------------------------------------------------------------------
     2775
     2776// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
    19242777ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
    1925    : DrawListInst(&context->DrawListSharedData)
    1926 {
    1927    Name = ImStrdup(name);
    1928    ID = ImHash(name, 0);
    1929    IDStack.push_back(ID);
    1930    Flags = 0;
    1931    Pos = ImVec2(0.0f, 0.0f);
    1932    Size = SizeFull = ImVec2(0.0f, 0.0f);
    1933    SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
    1934    WindowPadding = ImVec2(0.0f, 0.0f);
    1935    WindowRounding = 0.0f;
    1936    WindowBorderSize = 0.0f;
    1937    MoveId = GetID("#MOVE");
    1938    ChildId = 0;
    1939    Scroll = ImVec2(0.0f, 0.0f);
    1940    ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
    1941    ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
    1942    ScrollbarSizes = ImVec2(0.0f, 0.0f);
    1943    ScrollbarX = ScrollbarY = false;
    1944    Active = WasActive = false;
    1945    WriteAccessed = false;
    1946    Collapsed = false;
    1947    CollapseToggleWanted = false;
    1948    SkipItems = false;
    1949    Appearing = false;
    1950    CloseButton = false;
    1951    BeginOrderWithinParent = -1;
    1952    BeginOrderWithinContext = -1;
    1953    BeginCount = 0;
    1954    PopupId = 0;
    1955    AutoFitFramesX = AutoFitFramesY = -1;
    1956    AutoFitOnlyGrows = false;
    1957    AutoFitChildAxises = 0x00;
    1958    AutoPosLastDirection = ImGuiDir_None;
    1959    HiddenFrames = 0;
    1960    SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
    1961    SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
    1962 
    1963    LastFrameActive = -1;
    1964    ItemWidthDefault = 0.0f;
    1965    FontWindowScale = 1.0f;
    1966 
    1967    DrawList = &DrawListInst;
    1968    DrawList->_OwnerName = Name;
    1969    ParentWindow = NULL;
    1970    RootWindow = NULL;
    1971    RootWindowForTitleBarHighlight = NULL;
    1972    RootWindowForTabbing = NULL;
    1973    RootWindowForNav = NULL;
    1974 
    1975    NavLastIds[0] = NavLastIds[1] = 0;
    1976    NavRectRel[0] = NavRectRel[1] = ImRect();
    1977    NavLastChildNavWindow = NULL;
    1978 
    1979    FocusIdxAllCounter = FocusIdxTabCounter = -1;
    1980    FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX;
    1981    FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX;
     2778    : DrawListInst(&context->DrawListSharedData)
     2779{
     2780    Name = ImStrdup(name);
     2781    ID = ImHashStr(name);
     2782    IDStack.push_back(ID);
     2783    Flags = ImGuiWindowFlags_None;
     2784    Pos = ImVec2(0.0f, 0.0f);
     2785    Size = SizeFull = ImVec2(0.0f, 0.0f);
     2786    ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f);
     2787    WindowPadding = ImVec2(0.0f, 0.0f);
     2788    WindowRounding = 0.0f;
     2789    WindowBorderSize = 0.0f;
     2790    NameBufLen = (int)strlen(name) + 1;
     2791    MoveId = GetID("#MOVE");
     2792    ChildId = 0;
     2793    Scroll = ImVec2(0.0f, 0.0f);
     2794    ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
     2795    ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
     2796    ScrollbarSizes = ImVec2(0.0f, 0.0f);
     2797    ScrollbarX = ScrollbarY = false;
     2798    Active = WasActive = false;
     2799    WriteAccessed = false;
     2800    Collapsed = false;
     2801    WantCollapseToggle = false;
     2802    SkipItems = false;
     2803    Appearing = false;
     2804    Hidden = false;
     2805    IsFallbackWindow = false;
     2806    HasCloseButton = false;
     2807    ResizeBorderHeld = -1;
     2808    BeginCount = 0;
     2809    BeginOrderWithinParent = -1;
     2810    BeginOrderWithinContext = -1;
     2811    PopupId = 0;
     2812    AutoFitFramesX = AutoFitFramesY = -1;
     2813    AutoFitChildAxises = 0x00;
     2814    AutoFitOnlyGrows = false;
     2815    AutoPosLastDirection = ImGuiDir_None;
     2816    HiddenFramesCanSkipItems = HiddenFramesCannotSkipItems = 0;
     2817    SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
     2818    SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
     2819
     2820    InnerRect = ImRect(0.0f, 0.0f, 0.0f, 0.0f); // Clear so the InnerRect.GetSize() code in Begin() doesn't lead to overflow even if the result isn't used.
     2821
     2822    LastFrameActive = -1;
     2823    LastTimeActive = -1.0f;
     2824    ItemWidthDefault = 0.0f;
     2825    FontWindowScale = 1.0f;
     2826    SettingsOffset = -1;
     2827
     2828    DrawList = &DrawListInst;
     2829    DrawList->_OwnerName = Name;
     2830    ParentWindow = NULL;
     2831    RootWindow = NULL;
     2832    RootWindowForTitleBarHighlight = NULL;
     2833    RootWindowForNav = NULL;
     2834
     2835    NavLastIds[0] = NavLastIds[1] = 0;
     2836    NavRectRel[0] = NavRectRel[1] = ImRect();
     2837    NavLastChildNavWindow = NULL;
     2838
     2839    MemoryCompacted = false;
     2840    MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0;
    19822841}
    19832842
    19842843ImGuiWindow::~ImGuiWindow()
    19852844{
    1986    IM_ASSERT(DrawList == &DrawListInst);
    1987    IM_DELETE(Name);
    1988    for (int i = 0; i != ColumnsStorage.Size; i++)
    1989       ColumnsStorage[i].~ImGuiColumnsSet();
     2845    IM_ASSERT(DrawList == &DrawListInst);
     2846    IM_DELETE(Name);
     2847    for (int i = 0; i != ColumnsStorage.Size; i++)
     2848        ColumnsStorage[i].~ImGuiColumns();
    19902849}
    19912850
    19922851ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
    19932852{
    1994    ImGuiID seed = IDStack.back();
    1995    ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
    1996    ImGui::KeepAliveID(id);
    1997    return id;
     2853    ImGuiID seed = IDStack.back();
     2854    ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
     2855    ImGui::KeepAliveID(id);
     2856#ifdef IMGUI_ENABLE_TEST_ENGINE
     2857    ImGuiContext& g = *GImGui;
     2858    IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
     2859#endif
     2860    return id;
    19982861}
    19992862
    20002863ImGuiID ImGuiWindow::GetID(const void* ptr)
    20012864{
    2002    ImGuiID seed = IDStack.back();
    2003    ImGuiID id = ImHash(&ptr, sizeof(void*), seed);
    2004    ImGui::KeepAliveID(id);
    2005    return id;
     2865    ImGuiID seed = IDStack.back();
     2866    ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
     2867    ImGui::KeepAliveID(id);
     2868#ifdef IMGUI_ENABLE_TEST_ENGINE
     2869    ImGuiContext& g = *GImGui;
     2870    IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
     2871#endif
     2872    return id;
     2873}
     2874
     2875ImGuiID ImGuiWindow::GetID(int n)
     2876{
     2877    ImGuiID seed = IDStack.back();
     2878    ImGuiID id = ImHashData(&n, sizeof(n), seed);
     2879    ImGui::KeepAliveID(id);
     2880#ifdef IMGUI_ENABLE_TEST_ENGINE
     2881    ImGuiContext& g = *GImGui;
     2882    IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
     2883#endif
     2884    return id;
    20062885}
    20072886
    20082887ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
    20092888{
    2010    ImGuiID seed = IDStack.back();
    2011    return ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
     2889    ImGuiID seed = IDStack.back();
     2890    ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
     2891#ifdef IMGUI_ENABLE_TEST_ENGINE
     2892    ImGuiContext& g = *GImGui;
     2893    IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
     2894#endif
     2895    return id;
     2896}
     2897
     2898ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
     2899{
     2900    ImGuiID seed = IDStack.back();
     2901    ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
     2902#ifdef IMGUI_ENABLE_TEST_ENGINE
     2903    ImGuiContext& g = *GImGui;
     2904    IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
     2905#endif
     2906    return id;
     2907}
     2908
     2909ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
     2910{
     2911    ImGuiID seed = IDStack.back();
     2912    ImGuiID id = ImHashData(&n, sizeof(n), seed);
     2913#ifdef IMGUI_ENABLE_TEST_ENGINE
     2914    ImGuiContext& g = *GImGui;
     2915    IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
     2916#endif
     2917    return id;
    20122918}
    20132919
     
    20152921ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
    20162922{
    2017    ImGuiID seed = IDStack.back();
    2018    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) };
    2019    ImGuiID id = ImHash(&r_rel, sizeof(r_rel), seed);
    2020    ImGui::KeepAliveID(id);
    2021    return id;
    2022 }
    2023 
    2024 //-----------------------------------------------------------------------------
    2025 // Internal API exposed in imgui_internal.h
    2026 //-----------------------------------------------------------------------------
     2923    ImGuiID seed = IDStack.back();
     2924    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) };
     2925    ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
     2926    ImGui::KeepAliveID(id);
     2927    return id;
     2928}
    20272929
    20282930static void SetCurrentWindow(ImGuiWindow* window)
    20292931{
    2030    ImGuiContext& g = *GImGui;
    2031    g.CurrentWindow = window;
    2032    if (window)
    2033       g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
    2034 }
    2035 
    2036 static void SetNavID(ImGuiID id, int nav_layer)
    2037 {
    2038    ImGuiContext& g = *GImGui;
    2039    IM_ASSERT(g.NavWindow);
    2040    IM_ASSERT(nav_layer == 0 || nav_layer == 1);
    2041    g.NavId = id;
    2042    g.NavWindow->NavLastIds[nav_layer] = id;
    2043 }
    2044 
    2045 static void SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel)
    2046 {
    2047    ImGuiContext& g = *GImGui;
    2048    SetNavID(id, nav_layer);
    2049    g.NavWindow->NavRectRel[nav_layer] = rect_rel;
    2050    g.NavMousePosDirty = true;
    2051    g.NavDisableHighlight = false;
    2052    g.NavDisableMouseHover = true;
     2932    ImGuiContext& g = *GImGui;
     2933    g.CurrentWindow = window;
     2934    if (window)
     2935        g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
     2936}
     2937
     2938// Free up/compact internal window buffers, we can use this when a window becomes unused.
     2939// This is currently unused by the library, but you may call this yourself for easy GC.
     2940// Not freed:
     2941// - ImGuiWindow, ImGuiWindowSettings, Name
     2942// - StateStorage, ColumnsStorage (may hold useful data)
     2943// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
     2944void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
     2945{
     2946    window->MemoryCompacted = true;
     2947    window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
     2948    window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
     2949    window->IDStack.clear();
     2950    window->DrawList->_ClearFreeMemory();
     2951    window->DC.ChildWindows.clear();
     2952    window->DC.ItemFlagsStack.clear();
     2953    window->DC.ItemWidthStack.clear();
     2954    window->DC.TextWrapPosStack.clear();
     2955    window->DC.GroupStack.clear();
     2956}
     2957
     2958void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
     2959{
     2960    // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
     2961    // The other buffers tends to amortize much faster.
     2962    window->MemoryCompacted = false;
     2963    window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);
     2964    window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);
     2965    window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;
    20532966}
    20542967
    20552968void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
    20562969{
    2057    ImGuiContext& g = *GImGui;
    2058    g.ActiveIdIsJustActivated = (g.ActiveId != id);
    2059    if (g.ActiveIdIsJustActivated)
    2060       g.ActiveIdTimer = 0.0f;
    2061    g.ActiveId = id;
    2062    g.ActiveIdAllowNavDirFlags = 0;
    2063    g.ActiveIdAllowOverlap = false;
    2064    g.ActiveIdWindow = window;
    2065    if (id)
    2066    {
    2067       g.ActiveIdIsAlive = true;
    2068       g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
    2069    }
    2070 }
    2071 
    2072 ImGuiID ImGui::GetActiveID()
    2073 {
    2074    ImGuiContext& g = *GImGui;
    2075    return g.ActiveId;
    2076 }
    2077 
    2078 void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
    2079 {
    2080    ImGuiContext& g = *GImGui;
    2081    IM_ASSERT(id != 0);
    2082 
    2083    // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it.
    2084    const int nav_layer = window->DC.NavLayerCurrent;
    2085    if (g.NavWindow != window)
    2086       g.NavInitRequest = false;
    2087    g.NavId = id;
    2088    g.NavWindow = window;
    2089    g.NavLayer = nav_layer;
    2090    window->NavLastIds[nav_layer] = id;
    2091    if (window->DC.LastItemId == id)
    2092       window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
    2093 
    2094    if (g.ActiveIdSource == ImGuiInputSource_Nav)
    2095       g.NavDisableMouseHover = true;
    2096    else
    2097       g.NavDisableHighlight = true;
     2970    ImGuiContext& g = *GImGui;
     2971    g.ActiveIdIsJustActivated = (g.ActiveId != id);
     2972    if (g.ActiveIdIsJustActivated)
     2973    {
     2974        g.ActiveIdTimer = 0.0f;
     2975        g.ActiveIdHasBeenPressedBefore = false;
     2976        g.ActiveIdHasBeenEditedBefore = false;
     2977        if (id != 0)
     2978        {
     2979            g.LastActiveId = id;
     2980            g.LastActiveIdTimer = 0.0f;
     2981        }
     2982    }
     2983    g.ActiveId = id;
     2984    g.ActiveIdAllowOverlap = false;
     2985    g.ActiveIdNoClearOnFocusLoss = false;
     2986    g.ActiveIdWindow = window;
     2987    g.ActiveIdHasBeenEditedThisFrame = false;
     2988    if (id)
     2989    {
     2990        g.ActiveIdIsAlive = id;
     2991        g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
     2992    }
     2993
     2994    // Clear declaration of inputs claimed by the widget
     2995    // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
     2996    g.ActiveIdUsingNavDirMask = 0x00;
     2997    g.ActiveIdUsingNavInputMask = 0x00;
     2998    g.ActiveIdUsingKeyInputMask = 0x00;
    20982999}
    20993000
    21003001void ImGui::ClearActiveID()
    21013002{
    2102    SetActiveID(0, NULL);
     3003    SetActiveID(0, NULL); // g.ActiveId = 0;
    21033004}
    21043005
    21053006void ImGui::SetHoveredID(ImGuiID id)
    21063007{
    2107    ImGuiContext& g = *GImGui;
    2108    g.HoveredId = id;
    2109    g.HoveredIdAllowOverlap = false;
    2110    g.HoveredIdTimer = (id != 0 && g.HoveredIdPreviousFrame == id) ? (g.HoveredIdTimer + g.IO.DeltaTime) : 0.0f;
     3008    ImGuiContext& g = *GImGui;
     3009    g.HoveredId = id;
     3010    g.HoveredIdAllowOverlap = false;
     3011    if (id != 0 && g.HoveredIdPreviousFrame != id)
     3012        g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;
    21113013}
    21123014
    21133015ImGuiID ImGui::GetHoveredID()
    21143016{
    2115    ImGuiContext& g = *GImGui;
    2116    return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
     3017    ImGuiContext& g = *GImGui;
     3018    return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
    21173019}
    21183020
    21193021void ImGui::KeepAliveID(ImGuiID id)
    21203022{
    2121    ImGuiContext& g = *GImGui;
    2122    if (g.ActiveId == id)
    2123       g.ActiveIdIsAlive = true;
     3023    ImGuiContext& g = *GImGui;
     3024    if (g.ActiveId == id)
     3025        g.ActiveIdIsAlive = id;
     3026    if (g.ActiveIdPreviousFrame == id)
     3027        g.ActiveIdPreviousFrameIsAlive = true;
     3028}
     3029
     3030void ImGui::MarkItemEdited(ImGuiID id)
     3031{
     3032    // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
     3033    // 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.
     3034    ImGuiContext& g = *GImGui;
     3035    IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
     3036    IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
     3037    //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
     3038    g.ActiveIdHasBeenEditedThisFrame = true;
     3039    g.ActiveIdHasBeenEditedBefore = true;
     3040    g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
    21243041}
    21253042
    21263043static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
    21273044{
    2128    // An active popup disable hovering on other windows (apart from its own children)
    2129    // FIXME-OPT: This could be cached/stored within the window.
    2130    ImGuiContext& g = *GImGui;
    2131    if (g.NavWindow)
    2132       if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
    2133          if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
    2134          {
    2135             // For the purpose of those flags we differentiate "standard popup" from "modal popup"
    2136             // NB: The order of those two tests is important because Modal windows are also Popups.
    2137             if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
    2138                return false;
    2139             if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
    2140                return false;
    2141          }
    2142 
    2143    return true;
    2144 }
    2145 
    2146 // Advance cursor given item size for layout.
    2147 void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
    2148 {
    2149    ImGuiContext& g = *GImGui;
    2150    ImGuiWindow* window = g.CurrentWindow;
    2151    if (window->SkipItems)
    2152       return;
    2153 
    2154    // Always align ourselves on pixel boundaries
    2155    const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
    2156    const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
    2157    //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]
    2158    window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
    2159    window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y));
    2160    window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
    2161    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
    2162    //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
    2163 
    2164    window->DC.PrevLineHeight = line_height;
    2165    window->DC.PrevLineTextBaseOffset = text_base_offset;
    2166    window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f;
    2167 
    2168    // Horizontal layout mode
    2169    if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
    2170       SameLine();
    2171 }
    2172 
    2173 void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
    2174 {
    2175    ItemSize(bb.GetSize(), text_offset_y);
    2176 }
    2177 
    2178 static ImGuiDir NavScoreItemGetQuadrant(float dx, float dy)
    2179 {
    2180    if (fabsf(dx) > fabsf(dy))
    2181       return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
    2182    return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
    2183 }
    2184 
    2185 static float NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
    2186 {
    2187    if (a1 < b0)
    2188       return a1 - b0;
    2189    if (b1 < a0)
    2190       return a0 - b1;
    2191    return 0.0f;
    2192 }
    2193 
    2194 // Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057
    2195 static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
    2196 {
    2197    ImGuiContext& g = *GImGui;
    2198    ImGuiWindow* window = g.CurrentWindow;
    2199    if (g.NavLayer != window->DC.NavLayerCurrent)
    2200       return false;
    2201 
    2202    const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
    2203    g.NavScoringCount++;
    2204 
    2205    // We perform scoring on items bounding box clipped by their parent window on the other axis (clipping on our movement axis would give us equal scores for all clipped items)
    2206    if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
    2207    {
    2208       cand.Min.y = ImClamp(cand.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y);
    2209       cand.Max.y = ImClamp(cand.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y);
    2210    }
    2211    else
    2212    {
    2213       cand.Min.x = ImClamp(cand.Min.x, window->ClipRect.Min.x, window->ClipRect.Max.x);
    2214       cand.Max.x = ImClamp(cand.Max.x, window->ClipRect.Min.x, window->ClipRect.Max.x);
    2215    }
    2216 
    2217    // Compute distance between boxes
    2218    // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
    2219    float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
    2220    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
    2221    if (dby != 0.0f && dbx != 0.0f)
    2222       dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
    2223    float dist_box = fabsf(dbx) + fabsf(dby);
    2224 
    2225    // 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)
    2226    float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
    2227    float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
    2228    float dist_center = fabsf(dcx) + fabsf(dcy); // L1 metric (need this for our connectedness guarantee)
    2229 
    2230                                                 // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
    2231    ImGuiDir quadrant;
    2232    float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
    2233    if (dbx != 0.0f || dby != 0.0f)
    2234    {
    2235       // For non-overlapping boxes, use distance between boxes
    2236       dax = dbx;
    2237       day = dby;
    2238       dist_axial = dist_box;
    2239       quadrant = NavScoreItemGetQuadrant(dbx, dby);
    2240    }
    2241    else if (dcx != 0.0f || dcy != 0.0f)
    2242    {
    2243       // For overlapping boxes with different centers, use distance between centers
    2244       dax = dcx;
    2245       day = dcy;
    2246       dist_axial = dist_center;
    2247       quadrant = NavScoreItemGetQuadrant(dcx, dcy);
    2248    }
    2249    else
    2250    {
    2251       // 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)
    2252       quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
    2253    }
    2254 
    2255 #if IMGUI_DEBUG_NAV_SCORING
    2256    char buf[128];
    2257    if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max))
    2258    {
    2259       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]);
    2260       ImDrawList* draw_list = ImGui::GetOverlayDrawList();
    2261       draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255, 200, 0, 100));
    2262       draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255, 255, 0, 200));
    2263       draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + ImGui::CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40, 0, 0, 150));
    2264       draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
    2265    }
    2266    else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
    2267    {
    2268       if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
    2269       if (quadrant == g.NavMoveDir)
    2270       {
    2271          ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
    2272          ImDrawList* draw_list = ImGui::GetOverlayDrawList();
    2273          draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
    2274          draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
    2275       }
    2276    }
    2277 #endif
    2278 
    2279    // Is it in the quadrant we're interesting in moving to?
    2280    bool new_best = false;
    2281    if (quadrant == g.NavMoveDir)
    2282    {
    2283       // Does it beat the current best candidate?
    2284       if (dist_box < result->DistBox)
    2285       {
    2286          result->DistBox = dist_box;
    2287          result->DistCenter = dist_center;
    2288          return true;
    2289       }
    2290       if (dist_box == result->DistBox)
    2291       {
    2292          // Try using distance between center points to break ties
    2293          if (dist_center < result->DistCenter)
    2294          {
    2295             result->DistCenter = dist_center;
    2296             new_best = true;
    2297          }
    2298          else if (dist_center == result->DistCenter)
    2299          {
    2300             // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
    2301             // (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),
    2302             // 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.
    2303             if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
    2304                new_best = true;
    2305          }
    2306       }
    2307    }
    2308 
    2309    // 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
    2310    // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
    2311    // 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.
    2312    // 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.
    2313    // Disabling it may however lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
    2314    if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)  // Check axial match
    2315       if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
    2316          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))
    2317          {
    2318             result->DistAxial = dist_axial;
    2319             new_best = true;
    2320          }
    2321 
    2322    return new_best;
    2323 }
    2324 
    2325 static void NavSaveLastChildNavWindow(ImGuiWindow* child_window)
    2326 {
    2327    ImGuiWindow* parent_window = child_window;
    2328    while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
    2329       parent_window = parent_window->ParentWindow;
    2330    if (parent_window && parent_window != child_window)
    2331       parent_window->NavLastChildNavWindow = child_window;
    2332 }
    2333 
    2334 // Call when we are expected to land on Layer 0 after FocusWindow()
    2335 static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window)
    2336 {
    2337    return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window;
    2338 }
    2339 
    2340 static void NavRestoreLayer(int layer)
    2341 {
    2342    ImGuiContext& g = *GImGui;
    2343    g.NavLayer = layer;
    2344    if (layer == 0)
    2345       g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow);
    2346    if (layer == 0 && g.NavWindow->NavLastIds[0] != 0)
    2347       SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]);
    2348    else
    2349       ImGui::NavInitWindow(g.NavWindow, true);
    2350 }
    2351 
    2352 static inline void NavUpdateAnyRequestFlag()
    2353 {
    2354    ImGuiContext& g = *GImGui;
    2355    g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
    2356    if (g.NavAnyRequest)
    2357       IM_ASSERT(g.NavWindow != NULL);
    2358 }
    2359 
    2360 static bool NavMoveRequestButNoResultYet()
    2361 {
    2362    ImGuiContext& g = *GImGui;
    2363    return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
    2364 }
    2365 
    2366 void ImGui::NavMoveRequestCancel()
    2367 {
    2368    ImGuiContext& g = *GImGui;
    2369    g.NavMoveRequest = false;
    2370    NavUpdateAnyRequestFlag();
    2371 }
    2372 
    2373 // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
    2374 static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
    2375 {
    2376    ImGuiContext& g = *GImGui;
    2377    //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.
    2378    //    return;
    2379 
    2380    const ImGuiItemFlags item_flags = window->DC.ItemFlags;
    2381    const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
    2382    if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
    2383    {
    2384       // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
    2385       if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
    2386       {
    2387          g.NavInitResultId = id;
    2388          g.NavInitResultRectRel = nav_bb_rel;
    2389       }
    2390       if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
    2391       {
    2392          g.NavInitRequest = false; // Found a match, clear request
    2393          NavUpdateAnyRequestFlag();
    2394       }
    2395    }
    2396 
    2397    // Scoring for navigation
    2398    if (g.NavId != id && !(item_flags & ImGuiItemFlags_NoNav))
    2399    {
    2400       ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
    2401 #if IMGUI_DEBUG_NAV_SCORING
    2402       // [DEBUG] Score all items in NavWindow at all times
    2403       if (!g.NavMoveRequest)
    2404          g.NavMoveDir = g.NavMoveDirLast;
    2405       bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
    2406 #else
    2407       bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
    2408 #endif
    2409       if (new_best)
    2410       {
    2411          result->ID = id;
    2412          result->ParentID = window->IDStack.back();
    2413          result->Window = window;
    2414          result->RectRel = nav_bb_rel;
    2415       }
    2416    }
    2417 
    2418    // Update window-relative bounding box of navigated item
    2419    if (g.NavId == id)
    2420    {
    2421       g.NavWindow = window;                                           // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
    2422       g.NavLayer = window->DC.NavLayerCurrent;
    2423       g.NavIdIsAlive = true;
    2424       g.NavIdTabCounter = window->FocusIdxTabCounter;
    2425       window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel;    // Store item bounding box (relative to window position)
    2426    }
    2427 }
    2428 
    2429 // Declare item bounding box for clipping and interaction.
    2430 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
    2431 // declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
    2432 bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
    2433 {
    2434    ImGuiContext& g = *GImGui;
    2435    ImGuiWindow* window = g.CurrentWindow;
    2436 
    2437    if (id != 0)
    2438    {
    2439       // Navigation processing runs prior to clipping early-out
    2440       //  (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
    2441       //  (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window.
    2442       //      it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
    2443       //      We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick)
    2444       window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
    2445       if (g.NavId == id || g.NavAnyRequest)
    2446          if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
    2447             if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
    2448                NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
    2449    }
    2450 
    2451    window->DC.LastItemId = id;
    2452    window->DC.LastItemRect = bb;
    2453    window->DC.LastItemStatusFlags = 0;
    2454 
    2455    // Clipping test
    2456    const bool is_clipped = IsClippedEx(bb, id, false);
    2457    if (is_clipped)
    2458       return false;
    2459    //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
    2460 
    2461    // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
    2462    if (IsMouseHoveringRect(bb.Min, bb.Max))
    2463       window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
    2464    return true;
     3045    // An active popup disable hovering on other windows (apart from its own children)
     3046    // FIXME-OPT: This could be cached/stored within the window.
     3047    ImGuiContext& g = *GImGui;
     3048    if (g.NavWindow)
     3049        if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
     3050            if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
     3051            {
     3052                // For the purpose of those flags we differentiate "standard popup" from "modal popup"
     3053                // NB: The order of those two tests is important because Modal windows are also Popups.
     3054                if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
     3055                    return false;
     3056                if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
     3057                    return false;
     3058            }
     3059    return true;
    24653060}
    24663061
     
    24703065bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
    24713066{
    2472    ImGuiContext& g = *GImGui;
    2473    ImGuiWindow* window = g.CurrentWindow;
    2474    if (g.NavDisableMouseHover && !g.NavDisableHighlight)
    2475       return IsItemFocused();
    2476 
    2477    // Test for bounding box overlap, as updated as ItemAdd()
    2478    if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
    2479       return false;
    2480    IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0);   // Flags not supported by this function
    2481 
    2482                                                                                                 // Test if we are hovering the right window (our window could be behind another window)
    2483                                                                                                 // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself.
    2484                                                                                                 // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while.
    2485                                                                                                 //if (g.HoveredWindow != window)
    2486                                                                                                 //    return false;
    2487    if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
    2488       return false;
    2489 
    2490    // Test if another item is active (e.g. being dragged)
    2491    if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
    2492       if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
    2493          return false;
    2494 
    2495    // Test if interactions on this window are blocked by an active popup or modal
    2496    if (!IsWindowContentHoverable(window, flags))
    2497       return false;
    2498 
    2499    // Test if the item is disabled
    2500    if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
    2501       return false;
    2502 
    2503    // Special handling for the 1st item after Begin() which represent the title bar. When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect tht case.
    2504    if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
    2505       return false;
    2506    return true;
     3067    ImGuiContext& g = *GImGui;
     3068    ImGuiWindow* window = g.CurrentWindow;
     3069    if (g.NavDisableMouseHover && !g.NavDisableHighlight)
     3070        return IsItemFocused();
     3071
     3072    // Test for bounding box overlap, as updated as ItemAdd()
     3073    if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
     3074        return false;
     3075    IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0);   // Flags not supported by this function
     3076
     3077    // Test if we are hovering the right window (our window could be behind another window)
     3078    // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself.
     3079    // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while.
     3080    //if (g.HoveredWindow != window)
     3081    //    return false;
     3082    if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
     3083        return false;
     3084
     3085    // Test if another item is active (e.g. being dragged)
     3086    if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
     3087        if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
     3088            return false;
     3089
     3090    // Test if interactions on this window are blocked by an active popup or modal.
     3091    // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
     3092    if (!IsWindowContentHoverable(window, flags))
     3093        return false;
     3094
     3095    // Test if the item is disabled
     3096    if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
     3097        return false;
     3098
     3099    // Special handling for calling after Begin() which represent the title bar or tab.
     3100    // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
     3101    if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
     3102        return false;
     3103    return true;
    25073104}
    25083105
     
    25103107bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
    25113108{
    2512    ImGuiContext& g = *GImGui;
    2513    if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
    2514       return false;
    2515 
    2516    ImGuiWindow* window = g.CurrentWindow;
    2517    if (g.HoveredWindow != window)
    2518       return false;
    2519    if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
    2520       return false;
    2521    if (!IsMouseHoveringRect(bb.Min, bb.Max))
    2522       return false;
    2523    if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_Default))
    2524       return false;
    2525    if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
    2526       return false;
    2527 
    2528    SetHoveredID(id);
    2529    return true;
     3109    ImGuiContext& g = *GImGui;
     3110    if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
     3111        return false;
     3112
     3113    ImGuiWindow* window = g.CurrentWindow;
     3114    if (g.HoveredWindow != window)
     3115        return false;
     3116    if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
     3117        return false;
     3118    if (!IsMouseHoveringRect(bb.Min, bb.Max))
     3119        return false;
     3120    if (g.NavDisableMouseHover)
     3121        return false;
     3122    if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (window->DC.ItemFlags & ImGuiItemFlags_Disabled))
     3123    {
     3124        g.HoveredIdDisabled = true;
     3125        return false;
     3126    }
     3127
     3128    // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level
     3129    // hover test in widgets code. We could also decide to split this function is two.
     3130    if (id != 0)
     3131    {
     3132        SetHoveredID(id);
     3133
     3134        // [DEBUG] Item Picker tool!
     3135        // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making
     3136        // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered
     3137        // items if we perform the test in ItemAdd(), but that would incur a small runtime cost.
     3138        // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd().
     3139        if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id)
     3140            GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
     3141        if (g.DebugItemPickerBreakId == id)
     3142            IM_DEBUG_BREAK();
     3143    }
     3144
     3145    return true;
    25303146}
    25313147
    25323148bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
    25333149{
    2534    ImGuiContext& g = *GImGui;
    2535    ImGuiWindow* window = g.CurrentWindow;
    2536    if (!bb.Overlaps(window->ClipRect))
    2537       if (id == 0 || id != g.ActiveId)
    2538          if (clip_even_when_logged || !g.LogEnabled)
     3150    ImGuiContext& g = *GImGui;
     3151    ImGuiWindow* window = g.CurrentWindow;
     3152    if (!bb.Overlaps(window->ClipRect))
     3153        if (id == 0 || (id != g.ActiveId && id != g.NavId))
     3154            if (clip_even_when_logged || !g.LogEnabled)
     3155                return true;
     3156    return false;
     3157}
     3158
     3159// This is also inlined in ItemAdd()
     3160// Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect!
     3161void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
     3162{
     3163    window->DC.LastItemId = item_id;
     3164    window->DC.LastItemStatusFlags = item_flags;
     3165    window->DC.LastItemRect = item_rect;
     3166}
     3167
     3168// Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
     3169bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
     3170{
     3171    ImGuiContext& g = *GImGui;
     3172
     3173    // Increment counters
     3174    const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
     3175    window->DC.FocusCounterRegular++;
     3176    if (is_tab_stop)
     3177        window->DC.FocusCounterTabStop++;
     3178
     3179    // Process TAB/Shift-TAB to tab *OUT* of the currently focused item.
     3180    // (Note that we can always TAB out of a widget that doesn't allow tabbing in)
     3181    if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL)
     3182    {
     3183        g.FocusRequestNextWindow = window;
     3184        g.FocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
     3185    }
     3186
     3187    // Handle focus requests
     3188    if (g.FocusRequestCurrWindow == window)
     3189    {
     3190        if (window->DC.FocusCounterRegular == g.FocusRequestCurrCounterRegular)
    25393191            return true;
    2540    return false;
    2541 }
    2542 
    2543 bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop)
    2544 {
    2545    ImGuiContext& g = *GImGui;
    2546 
    2547    const bool allow_keyboard_focus = (window->DC.ItemFlags & (ImGuiItemFlags_AllowKeyboardFocus | ImGuiItemFlags_Disabled)) == ImGuiItemFlags_AllowKeyboardFocus;
    2548    window->FocusIdxAllCounter++;
    2549    if (allow_keyboard_focus)
    2550       window->FocusIdxTabCounter++;
    2551 
    2552    // Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item.
    2553    // Note that we can always TAB out of a widget that doesn't allow tabbing in.
    2554    if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab))
    2555       window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
    2556 
    2557    if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent)
    2558       return true;
    2559    if (allow_keyboard_focus && window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent)
    2560    {
    2561       g.NavJustTabbedId = id;
    2562       return true;
    2563    }
    2564 
    2565    return false;
     3192        if (is_tab_stop && window->DC.FocusCounterTabStop == g.FocusRequestCurrCounterTabStop)
     3193        {
     3194            g.NavJustTabbedId = id;
     3195            return true;
     3196        }
     3197
     3198        // If another item is about to be focused, we clear our own active id
     3199        if (g.ActiveId == id)
     3200            ClearActiveID();
     3201    }
     3202
     3203    return false;
    25663204}
    25673205
    25683206void ImGui::FocusableItemUnregister(ImGuiWindow* window)
    25693207{
    2570    window->FocusIdxAllCounter--;
    2571    window->FocusIdxTabCounter--;
    2572 }
    2573 
    2574 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y)
    2575 {
    2576    ImGuiContext& g = *GImGui;
    2577    ImVec2 content_max;
    2578    if (size.x < 0.0f || size.y < 0.0f)
    2579       content_max = g.CurrentWindow->Pos + GetContentRegionMax();
    2580    if (size.x <= 0.0f)
    2581       size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x;
    2582    if (size.y <= 0.0f)
    2583       size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y;
    2584    return size;
     3208    window->DC.FocusCounterRegular--;
     3209    window->DC.FocusCounterTabStop--;
    25853210}
    25863211
    25873212float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
    25883213{
    2589    if (wrap_pos_x < 0.0f)
    2590       return 0.0f;
    2591 
    2592    ImGuiWindow* window = GetCurrentWindowRead();
    2593    if (wrap_pos_x == 0.0f)
    2594       wrap_pos_x = GetContentRegionMax().x + window->Pos.x;
    2595    else if (wrap_pos_x > 0.0f)
    2596       wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
    2597 
    2598    return ImMax(wrap_pos_x - pos.x, 1.0f);
    2599 }
    2600 
    2601 //-----------------------------------------------------------------------------
    2602 
    2603 void* ImGui::MemAlloc(size_t sz)
    2604 {
    2605    GImAllocatorActiveAllocationsCount++;
    2606    return GImAllocatorAllocFunc(sz, GImAllocatorUserData);
    2607 }
    2608 
     3214    if (wrap_pos_x < 0.0f)
     3215        return 0.0f;
     3216
     3217    ImGuiContext& g = *GImGui;
     3218    ImGuiWindow* window = g.CurrentWindow;
     3219    if (wrap_pos_x == 0.0f)
     3220    {
     3221        // We could decide to setup a default wrapping max point for auto-resizing windows,
     3222        // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function?
     3223        //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize))
     3224        //    wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x);
     3225        //else
     3226        wrap_pos_x = window->WorkRect.Max.x;
     3227    }
     3228    else if (wrap_pos_x > 0.0f)
     3229    {
     3230        wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
     3231    }
     3232
     3233    return ImMax(wrap_pos_x - pos.x, 1.0f);
     3234}
     3235
     3236// IM_ALLOC() == ImGui::MemAlloc()
     3237void* ImGui::MemAlloc(size_t size)
     3238{
     3239    if (ImGuiContext* ctx = GImGui)
     3240        ctx->IO.MetricsActiveAllocations++;
     3241    return GImAllocatorAllocFunc(size, GImAllocatorUserData);
     3242}
     3243
     3244// IM_FREE() == ImGui::MemFree()
    26093245void ImGui::MemFree(void* ptr)
    26103246{
    2611    if (ptr) GImAllocatorActiveAllocationsCount--;
    2612    return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
     3247    if (ptr)
     3248        if (ImGuiContext* ctx = GImGui)
     3249            ctx->IO.MetricsActiveAllocations--;
     3250    return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
    26133251}
    26143252
    26153253const char* ImGui::GetClipboardText()
    26163254{
    2617    return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : "";
     3255    ImGuiContext& g = *GImGui;
     3256    return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : "";
    26183257}
    26193258
    26203259void ImGui::SetClipboardText(const char* text)
    26213260{
    2622    if (GImGui->IO.SetClipboardTextFn)
    2623       GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text);
     3261    ImGuiContext& g = *GImGui;
     3262    if (g.IO.SetClipboardTextFn)
     3263        g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text);
    26243264}
    26253265
    26263266const char* ImGui::GetVersion()
    26273267{
    2628    return IMGUI_VERSION;
    2629 }
    2630 
    2631 // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
     3268    return IMGUI_VERSION;
     3269}
     3270
     3271// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
    26323272// 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
    26333273ImGuiContext* ImGui::GetCurrentContext()
    26343274{
    2635    return GImGui;
     3275    return GImGui;
    26363276}
    26373277
     
    26393279{
    26403280#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
    2641    IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
     3281    IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
    26423282#else
    2643    GImGui = ctx;
     3283    GImGui = ctx;
    26443284#endif
    26453285}
    26463286
    2647 // Helper function to verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
    2648 // If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. you may see different structures from what imgui.cpp sees which is highly problematic.
    2649 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)
    2650 {
    2651    bool error = false;
    2652    if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatch version string!"); }
    2653    if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
    2654    if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
    2655    if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
    2656    if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
    2657    if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
    2658    return !error;
    2659 }
    2660 
    2661 void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data)
    2662 {
    2663    GImAllocatorAllocFunc = alloc_func;
    2664    GImAllocatorFreeFunc = free_func;
    2665    GImAllocatorUserData = user_data;
     3287void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
     3288{
     3289    GImAllocatorAllocFunc = alloc_func;
     3290    GImAllocatorFreeFunc = free_func;
     3291    GImAllocatorUserData = user_data;
    26663292}
    26673293
    26683294ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
    26693295{
    2670    ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
    2671    if (GImGui == NULL)
    2672       SetCurrentContext(ctx);
    2673    Initialize(ctx);
    2674    return ctx;
     3296    ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
     3297    if (GImGui == NULL)
     3298        SetCurrentContext(ctx);
     3299    Initialize(ctx);
     3300    return ctx;
    26753301}
    26763302
    26773303void ImGui::DestroyContext(ImGuiContext* ctx)
    26783304{
    2679    if (ctx == NULL)
    2680       ctx = GImGui;
    2681    Shutdown(ctx);
    2682    if (GImGui == ctx)
    2683       SetCurrentContext(NULL);
    2684    IM_DELETE(ctx);
     3305    if (ctx == NULL)
     3306        ctx = GImGui;
     3307    Shutdown(ctx);
     3308    if (GImGui == ctx)
     3309        SetCurrentContext(NULL);
     3310    IM_DELETE(ctx);
    26853311}
    26863312
    26873313ImGuiIO& ImGui::GetIO()
    26883314{
    2689    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
    2690    return GImGui->IO;
    2691 }
    2692 
    2693 ImGuiStyle& ImGui::GetStyle()
    2694 {
    2695    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
    2696    return GImGui->Style;
     3315    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
     3316    return GImGui->IO;
    26973317}
    26983318
     
    27003320ImDrawData* ImGui::GetDrawData()
    27013321{
    2702    ImGuiContext& g = *GImGui;
    2703    return g.DrawData.Valid ? &g.DrawData : NULL;
    2704 }
    2705 
    2706 float ImGui::GetTime()
    2707 {
    2708    return GImGui->Time;
     3322    ImGuiContext& g = *GImGui;
     3323    return g.DrawData.Valid ? &g.DrawData : NULL;
     3324}
     3325
     3326double ImGui::GetTime()
     3327{
     3328    return GImGui->Time;
    27093329}
    27103330
    27113331int ImGui::GetFrameCount()
    27123332{
    2713    return GImGui->FrameCount;
    2714 }
    2715 
    2716 ImDrawList* ImGui::GetOverlayDrawList()
    2717 {
    2718    return &GImGui->OverlayDrawList;
     3333    return GImGui->FrameCount;
     3334}
     3335
     3336ImDrawList* ImGui::GetBackgroundDrawList()
     3337{
     3338    return &GImGui->BackgroundDrawList;
     3339}
     3340
     3341ImDrawList* ImGui::GetForegroundDrawList()
     3342{
     3343    return &GImGui->ForegroundDrawList;
    27193344}
    27203345
    27213346ImDrawListSharedData* ImGui::GetDrawListSharedData()
    27223347{
    2723    return &GImGui->DrawListSharedData;
    2724 }
    2725 
    2726 // This needs to be called before we submit any widget (aka in or before Begin)
    2727 void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
    2728 {
    2729    ImGuiContext& g = *GImGui;
    2730    IM_ASSERT(window == g.NavWindow);
    2731    bool init_for_nav = false;
    2732    if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
    2733       if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
    2734          init_for_nav = true;
    2735    if (init_for_nav)
    2736    {
    2737       SetNavID(0, g.NavLayer);
    2738       g.NavInitRequest = true;
    2739       g.NavInitRequestFromMove = false;
    2740       g.NavInitResultId = 0;
    2741       g.NavInitResultRectRel = ImRect();
    2742       NavUpdateAnyRequestFlag();
    2743    }
    2744    else
    2745    {
    2746       g.NavId = window->NavLastIds[0];
    2747    }
    2748 }
    2749 
    2750 static ImVec2 NavCalcPreferredRefPos()
    2751 {
    2752    ImGuiContext& g = *GImGui;
    2753    if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow)
    2754       return ImFloor(g.IO.MousePos);
    2755 
    2756    // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item
    2757    const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
    2758    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()));
    2759    ImRect visible_rect = GetViewportRect();
    2760    return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max));   // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta.
    2761 }
    2762 
    2763 static int FindWindowIndex(ImGuiWindow* window) // FIXME-OPT O(N)
    2764 {
    2765    ImGuiContext& g = *GImGui;
    2766    for (int i = g.Windows.Size - 1; i >= 0; i--)
    2767       if (g.Windows[i] == window)
    2768          return i;
    2769    return -1;
    2770 }
    2771 
    2772 static ImGuiWindow* FindWindowNavigable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
    2773 {
    2774    ImGuiContext& g = *GImGui;
    2775    for (int i = i_start; i >= 0 && i < g.Windows.Size && i != i_stop; i += dir)
    2776       if (ImGui::IsWindowNavFocusable(g.Windows[i]))
    2777          return g.Windows[i];
    2778    return NULL;
    2779 }
    2780 
    2781 float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
    2782 {
    2783    ImGuiContext& g = *GImGui;
    2784    if (mode == ImGuiInputReadMode_Down)
    2785       return g.IO.NavInputs[n];                         // Instant, read analog input (0.0f..1.0f, as provided by user)
    2786 
    2787    const float t = g.IO.NavInputsDownDuration[n];
    2788    if (t < 0.0f && mode == ImGuiInputReadMode_Released)  // Return 1.0f when just released, no repeat, ignore analog input.
    2789       return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
    2790    if (t < 0.0f)
    2791       return 0.0f;
    2792    if (mode == ImGuiInputReadMode_Pressed)               // Return 1.0f when just pressed, no repeat, ignore analog input.
    2793       return (t == 0.0f) ? 1.0f : 0.0f;
    2794    if (mode == ImGuiInputReadMode_Repeat)
    2795       return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f);
    2796    if (mode == ImGuiInputReadMode_RepeatSlow)
    2797       return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f);
    2798    if (mode == ImGuiInputReadMode_RepeatFast)
    2799       return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f);
    2800    return 0.0f;
    2801 }
    2802 
    2803 // Equivalent of IsKeyDown() for NavInputs[]
    2804 static bool IsNavInputDown(ImGuiNavInput n)
    2805 {
    2806    return GImGui->IO.NavInputs[n] > 0.0f;
    2807 }
    2808 
    2809 // Equivalent of IsKeyPressed() for NavInputs[]
    2810 static bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode)
    2811 {
    2812    return ImGui::GetNavInputAmount(n, mode) > 0.0f;
    2813 }
    2814 
    2815 static bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode)
    2816 {
    2817    return (ImGui::GetNavInputAmount(n1, mode) + ImGui::GetNavInputAmount(n2, mode)) > 0.0f;
    2818 }
    2819 
    2820 ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
    2821 {
    2822    ImVec2 delta(0.0f, 0.0f);
    2823    if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
    2824       delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode));
    2825    if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
    2826       delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode));
    2827    if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
    2828       delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
    2829    if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
    2830       delta *= slow_factor;
    2831    if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
    2832       delta *= fast_factor;
    2833    return delta;
    2834 }
    2835 
    2836 static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
    2837 {
    2838    ImGuiContext& g = *GImGui;
    2839    IM_ASSERT(g.NavWindowingTarget);
    2840    if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
    2841       return;
    2842 
    2843    const int i_current = FindWindowIndex(g.NavWindowingTarget);
    2844    ImGuiWindow* window_target = FindWindowNavigable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
    2845    if (!window_target)
    2846       window_target = FindWindowNavigable((focus_change_dir < 0) ? (g.Windows.Size - 1) : 0, i_current, focus_change_dir);
    2847    g.NavWindowingTarget = window_target;
    2848    g.NavWindowingToggleLayer = false;
    2849 }
    2850 
    2851 // Window management mode (hold to: change focus/move/resize, tap to: toggle menu layer)
    2852 static void ImGui::NavUpdateWindowing()
    2853 {
    2854    ImGuiContext& g = *GImGui;
    2855    ImGuiWindow* apply_focus_window = NULL;
    2856    bool apply_toggle_layer = false;
    2857 
    2858    bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
    2859    bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
    2860    if (start_windowing_with_gamepad || start_windowing_with_keyboard)
    2861       if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavigable(g.Windows.Size - 1, -INT_MAX, -1))
    2862       {
    2863          g.NavWindowingTarget = window->RootWindowForTabbing;
    2864          g.NavWindowingHighlightTimer = g.NavWindowingHighlightAlpha = 0.0f;
    2865          g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
    2866          g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
    2867       }
    2868 
    2869    // Gamepad update
    2870    g.NavWindowingHighlightTimer += g.IO.DeltaTime;
    2871    if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad)
    2872    {
    2873       // 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
    2874       g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.20f) / 0.05f));
    2875 
    2876       // Select window to focus
    2877       const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
    2878       if (focus_change_dir != 0)
    2879       {
    2880          NavUpdateWindowingHighlightWindow(focus_change_dir);
    2881          g.NavWindowingHighlightAlpha = 1.0f;
    2882       }
    2883 
    2884       // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most)
    2885       if (!IsNavInputDown(ImGuiNavInput_Menu))
    2886       {
    2887          g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
    2888          if (g.NavWindowingToggleLayer && g.NavWindow)
    2889             apply_toggle_layer = true;
    2890          else if (!g.NavWindowingToggleLayer)
    2891             apply_focus_window = g.NavWindowingTarget;
    2892          g.NavWindowingTarget = NULL;
    2893       }
    2894    }
    2895 
    2896    // Keyboard: Focus
    2897    if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard)
    2898    {
    2899       // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
    2900       g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingHighlightTimer - 0.15f) / 0.04f)); // 1.0f
    2901       if (IsKeyPressedMap(ImGuiKey_Tab, true))
    2902          NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
    2903       if (!g.IO.KeyCtrl)
    2904          apply_focus_window = g.NavWindowingTarget;
    2905    }
    2906 
    2907    // Keyboard: Press and Release ALT to toggle menu layer
    2908    // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB
    2909    if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
    2910       if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
    2911          apply_toggle_layer = true;
    2912 
    2913    // Move window
    2914    if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
    2915    {
    2916       ImVec2 move_delta;
    2917       if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift)
    2918          move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
    2919       if (g.NavInputSource == ImGuiInputSource_NavGamepad)
    2920          move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
    2921       if (move_delta.x != 0.0f || move_delta.y != 0.0f)
    2922       {
    2923          const float NAV_MOVE_SPEED = 800.0f;
    2924          const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well
    2925          g.NavWindowingTarget->Pos += move_delta * move_speed;
    2926          g.NavDisableMouseHover = true;
    2927          MarkIniSettingsDirty(g.NavWindowingTarget);
    2928       }
    2929    }
    2930 
    2931    // Apply final focus
    2932    if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindowForTabbing))
    2933    {
    2934       g.NavDisableHighlight = false;
    2935       g.NavDisableMouseHover = true;
    2936       apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
    2937       ClosePopupsOverWindow(apply_focus_window);
    2938       FocusWindow(apply_focus_window);
    2939       if (apply_focus_window->NavLastIds[0] == 0)
    2940          NavInitWindow(apply_focus_window, false);
    2941 
    2942       // If the window only has a menu layer, select it directly
    2943       if (apply_focus_window->DC.NavLayerActiveMask == (1 << 1))
    2944          g.NavLayer = 1;
    2945    }
    2946    if (apply_focus_window)
    2947       g.NavWindowingTarget = NULL;
    2948 
    2949    // Apply menu/layer toggle
    2950    if (apply_toggle_layer && g.NavWindow)
    2951    {
    2952       ImGuiWindow* new_nav_window = g.NavWindow;
    2953       while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
    2954          new_nav_window = new_nav_window->ParentWindow;
    2955       if (new_nav_window != g.NavWindow)
    2956       {
    2957          ImGuiWindow* old_nav_window = g.NavWindow;
    2958          FocusWindow(new_nav_window);
    2959          new_nav_window->NavLastChildNavWindow = old_nav_window;
    2960       }
    2961       g.NavDisableHighlight = false;
    2962       g.NavDisableMouseHover = true;
    2963       NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0);
    2964    }
    2965 }
    2966 
    2967 // NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated.
    2968 static void NavScrollToBringItemIntoView(ImGuiWindow* window, ImRect& item_rect_rel)
    2969 {
    2970    // Scroll to keep newly navigated item fully into view
    2971    ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
    2972    //g.OverlayDrawList.AddRect(window->Pos + window_rect_rel.Min, window->Pos + window_rect_rel.Max, IM_COL32_WHITE); // [DEBUG]
    2973    if (window_rect_rel.Contains(item_rect_rel))
    2974       return;
    2975 
    2976    ImGuiContext& g = *GImGui;
    2977    if (window->ScrollbarX && item_rect_rel.Min.x < window_rect_rel.Min.x)
    2978    {
    2979       window->ScrollTarget.x = item_rect_rel.Min.x + window->Scroll.x - g.Style.ItemSpacing.x;
    2980       window->ScrollTargetCenterRatio.x = 0.0f;
    2981    }
    2982    else if (window->ScrollbarX && item_rect_rel.Max.x >= window_rect_rel.Max.x)
    2983    {
    2984       window->ScrollTarget.x = item_rect_rel.Max.x + window->Scroll.x + g.Style.ItemSpacing.x;
    2985       window->ScrollTargetCenterRatio.x = 1.0f;
    2986    }
    2987    if (item_rect_rel.Min.y < window_rect_rel.Min.y)
    2988    {
    2989       window->ScrollTarget.y = item_rect_rel.Min.y + window->Scroll.y - g.Style.ItemSpacing.y;
    2990       window->ScrollTargetCenterRatio.y = 0.0f;
    2991    }
    2992    else if (item_rect_rel.Max.y >= window_rect_rel.Max.y)
    2993    {
    2994       window->ScrollTarget.y = item_rect_rel.Max.y + window->Scroll.y + g.Style.ItemSpacing.y;
    2995       window->ScrollTargetCenterRatio.y = 1.0f;
    2996    }
    2997 
    2998    // Estimate upcoming scroll so we can offset our relative mouse position so mouse position can be applied immediately (under this block)
    2999    ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
    3000    item_rect_rel.Translate(window->Scroll - next_scroll);
    3001 }
    3002 
    3003 static void ImGui::NavUpdate()
    3004 {
    3005    ImGuiContext& g = *GImGui;
    3006    g.IO.WantSetMousePos = false;
    3007 
    3008 #if 0
    3009    if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
     3348    return &GImGui->DrawListSharedData;
     3349}
     3350
     3351void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
     3352{
     3353    // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
     3354    // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
     3355    // This is because we want ActiveId to be set even when the window is not permitted to move.
     3356    ImGuiContext& g = *GImGui;
     3357    FocusWindow(window);
     3358    SetActiveID(window->MoveId, window);
     3359    g.NavDisableHighlight = true;
     3360    g.ActiveIdNoClearOnFocusLoss = true;
     3361    g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos;
     3362
     3363    bool can_move_window = true;
     3364    if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove))
     3365        can_move_window = false;
     3366    if (can_move_window)
     3367        g.MovingWindow = window;
     3368}
     3369
     3370// Handle mouse moving window
     3371// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
     3372// FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId.
     3373// This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs,
     3374// but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other.
     3375void ImGui::UpdateMouseMovingWindowNewFrame()
     3376{
     3377    ImGuiContext& g = *GImGui;
     3378    if (g.MovingWindow != NULL)
     3379    {
     3380        // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
     3381        // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
     3382        KeepAliveID(g.ActiveId);
     3383        IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);
     3384        ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
     3385        if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
     3386        {
     3387            ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
     3388            if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
     3389            {
     3390                MarkIniSettingsDirty(moving_window);
     3391                SetWindowPos(moving_window, pos, ImGuiCond_Always);
     3392            }
     3393            FocusWindow(g.MovingWindow);
     3394        }
     3395        else
     3396        {
     3397            ClearActiveID();
     3398            g.MovingWindow = NULL;
     3399        }
     3400    }
     3401    else
     3402    {
     3403        // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
     3404        if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
     3405        {
     3406            KeepAliveID(g.ActiveId);
     3407            if (!g.IO.MouseDown[0])
     3408                ClearActiveID();
     3409        }
     3410    }
     3411}
     3412
     3413// Initiate moving window when clicking on empty space or title bar.
     3414// Handle left-click and right-click focus.
     3415void ImGui::UpdateMouseMovingWindowEndFrame()
     3416{
     3417    ImGuiContext& g = *GImGui;
     3418    if (g.ActiveId != 0 || g.HoveredId != 0)
     3419        return;
     3420
     3421    // Unless we just made a window/popup appear
     3422    if (g.NavWindow && g.NavWindow->Appearing)
     3423        return;
     3424
     3425    // Click on empty space to focus window and start moving (after we're done with all our widgets)
     3426    if (g.IO.MouseClicked[0])
     3427    {
     3428        // Handle the edge case of a popup being closed while clicking in its empty space.
     3429        // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more.
     3430        ImGuiWindow* root_window = g.HoveredRootWindow;
     3431        const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);
     3432
     3433        if (root_window != NULL && !is_closed_popup)
     3434        {
     3435            StartMouseMovingWindow(g.HoveredWindow);
     3436
     3437            // Cancel moving if clicked outside of title bar
     3438            if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar))
     3439                if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
     3440                    g.MovingWindow = NULL;
     3441
     3442            // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already)
     3443            if (g.HoveredIdDisabled)
     3444                g.MovingWindow = NULL;
     3445        }
     3446        else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
     3447        {
     3448            // Clicking on void disable focus
     3449            FocusWindow(NULL);
     3450        }
     3451    }
     3452
     3453    // With right mouse button we close popups without changing focus based on where the mouse is aimed
     3454    // Instead, focus will be restored to the window under the bottom-most closed popup.
     3455    // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
     3456    if (g.IO.MouseClicked[1])
     3457    {
     3458        // Find the top-most window between HoveredWindow and the top-most Modal Window.
     3459        // This is where we can trim the popup stack.
     3460        ImGuiWindow* modal = GetTopMostPopupModal();
     3461        bool hovered_window_above_modal = false;
     3462        if (modal == NULL)
     3463            hovered_window_above_modal = true;
     3464        for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
     3465        {
     3466            ImGuiWindow* window = g.Windows[i];
     3467            if (window == modal)
     3468                break;
     3469            if (window == g.HoveredWindow)
     3470                hovered_window_above_modal = true;
     3471        }
     3472        ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);
     3473    }
     3474}
     3475
     3476static bool IsWindowActiveAndVisible(ImGuiWindow* window)
     3477{
     3478    return (window->Active) && (!window->Hidden);
     3479}
     3480
     3481static void ImGui::UpdateMouseInputs()
     3482{
     3483    ImGuiContext& g = *GImGui;
     3484
     3485    // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
     3486    if (IsMousePosValid(&g.IO.MousePos))
     3487        g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos);
     3488
     3489    // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
     3490    if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
     3491        g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
     3492    else
     3493        g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
     3494    if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
     3495        g.NavDisableMouseHover = false;
     3496
     3497    g.IO.MousePosPrev = g.IO.MousePos;
     3498    for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
     3499    {
     3500        g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
     3501        g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
     3502        g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
     3503        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;
     3504        g.IO.MouseDoubleClicked[i] = false;
     3505        if (g.IO.MouseClicked[i])
     3506        {
     3507            if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime)
     3508            {
     3509                ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
     3510                if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
     3511                    g.IO.MouseDoubleClicked[i] = true;
     3512                g.IO.MouseClickedTime[i] = -g.IO.MouseDoubleClickTime * 2.0f; // Mark as "old enough" so the third click isn't turned into a double-click
     3513            }
     3514            else
     3515            {
     3516                g.IO.MouseClickedTime[i] = g.Time;
     3517            }
     3518            g.IO.MouseClickedPos[i] = g.IO.MousePos;
     3519            g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i];
     3520            g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
     3521            g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
     3522        }
     3523        else if (g.IO.MouseDown[i])
     3524        {
     3525            // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold
     3526            ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
     3527            g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos));
     3528            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);
     3529            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);
     3530        }
     3531        if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i])
     3532            g.IO.MouseDownWasDoubleClick[i] = false;
     3533        if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
     3534            g.NavDisableMouseHover = false;
     3535    }
     3536}
     3537
     3538static void StartLockWheelingWindow(ImGuiWindow* window)
     3539{
     3540    ImGuiContext& g = *GImGui;
     3541    if (g.WheelingWindow == window)
     3542        return;
     3543    g.WheelingWindow = window;
     3544    g.WheelingWindowRefMousePos = g.IO.MousePos;
     3545    g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER;
     3546}
     3547
     3548void ImGui::UpdateMouseWheel()
     3549{
     3550    ImGuiContext& g = *GImGui;
     3551
     3552    // Reset the locked window if we move the mouse or after the timer elapses
     3553    if (g.WheelingWindow != NULL)
     3554    {
     3555        g.WheelingWindowTimer -= g.IO.DeltaTime;
     3556        if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)
     3557            g.WheelingWindowTimer = 0.0f;
     3558        if (g.WheelingWindowTimer <= 0.0f)
     3559        {
     3560            g.WheelingWindow = NULL;
     3561            g.WheelingWindowTimer = 0.0f;
     3562        }
     3563    }
     3564
     3565    if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
     3566        return;
     3567
     3568    ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
     3569    if (!window || window->Collapsed)
     3570        return;
     3571
     3572    // Zoom / Scale window
     3573    // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
     3574    if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
     3575    {
     3576        StartLockWheelingWindow(window);
     3577        const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
     3578        const float scale = new_font_scale / window->FontWindowScale;
     3579        window->FontWindowScale = new_font_scale;
     3580        if (!(window->Flags & ImGuiWindowFlags_ChildWindow))
     3581        {
     3582            const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
     3583            SetWindowPos(window, window->Pos + offset, 0);
     3584            window->Size = ImFloor(window->Size * scale);
     3585            window->SizeFull = ImFloor(window->SizeFull * scale);
     3586        }
     3587        return;
     3588    }
     3589
     3590    // Mouse wheel scrolling
     3591    // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent
     3592
     3593    // Vertical Mouse Wheel scrolling
     3594    const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
     3595    if (wheel_y != 0.0f && !g.IO.KeyCtrl)
     3596    {
     3597        StartLockWheelingWindow(window);
     3598        while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
     3599            window = window->ParentWindow;
     3600        if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
     3601        {
     3602            float max_step = window->InnerRect.GetHeight() * 0.67f;
     3603            float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
     3604            SetScrollY(window, window->Scroll.y - wheel_y * scroll_step);
     3605        }
     3606    }
     3607
     3608    // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
     3609    const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
     3610    if (wheel_x != 0.0f && !g.IO.KeyCtrl)
     3611    {
     3612        StartLockWheelingWindow(window);
     3613        while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
     3614            window = window->ParentWindow;
     3615        if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
     3616        {
     3617            float max_step = window->InnerRect.GetWidth() * 0.67f;
     3618            float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
     3619            SetScrollX(window, window->Scroll.x - wheel_x * scroll_step);
     3620        }
     3621    }
     3622}
     3623
     3624void ImGui::UpdateTabFocus()
     3625{
     3626    ImGuiContext& g = *GImGui;
     3627
     3628    // Pressing TAB activate widget focus
     3629    g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
     3630    if (g.ActiveId == 0 && g.FocusTabPressed)
     3631    {
     3632        // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
     3633        // manipulate the Next fields even, even though they will be turned into Curr fields by the code below.
     3634        g.FocusRequestNextWindow = g.NavWindow;
     3635        g.FocusRequestNextCounterRegular = INT_MAX;
     3636        if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
     3637            g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
     3638        else
     3639            g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
     3640    }
     3641
     3642    // Turn queued focus request into current one
     3643    g.FocusRequestCurrWindow = NULL;
     3644    g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX;
     3645    if (g.FocusRequestNextWindow != NULL)
     3646    {
     3647        ImGuiWindow* window = g.FocusRequestNextWindow;
     3648        g.FocusRequestCurrWindow = window;
     3649        if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1)
     3650            g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1);
     3651        if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1)
     3652            g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1);
     3653        g.FocusRequestNextWindow = NULL;
     3654        g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX;
     3655    }
     3656
     3657    g.NavIdTabCounter = INT_MAX;
     3658}
     3659
     3660// 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)
     3661void ImGui::UpdateHoveredWindowAndCaptureFlags()
     3662{
     3663    ImGuiContext& g = *GImGui;
     3664
     3665    // Find the window hovered by mouse:
     3666    // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
     3667    // - 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.
     3668    // - 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.
     3669    bool clear_hovered_windows = false;
     3670    FindHoveredWindow();
     3671
     3672    // Modal windows prevents mouse from hovering behind them.
     3673    ImGuiWindow* modal_window = GetTopMostPopupModal();
     3674    if (modal_window && g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
     3675        clear_hovered_windows = true;
     3676
     3677    // Disabled mouse?
     3678    if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
     3679        clear_hovered_windows = true;
     3680
     3681    // 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.
     3682    int mouse_earliest_button_down = -1;
     3683    bool mouse_any_down = false;
     3684    for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
     3685    {
     3686        if (g.IO.MouseClicked[i])
     3687            g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (g.OpenPopupStack.Size > 0);
     3688        mouse_any_down |= g.IO.MouseDown[i];
     3689        if (g.IO.MouseDown[i])
     3690            if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
     3691                mouse_earliest_button_down = i;
     3692    }
     3693    const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
     3694
     3695    // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
     3696    // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
     3697    const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
     3698    if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
     3699        clear_hovered_windows = true;
     3700
     3701    if (clear_hovered_windows)
     3702        g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
     3703
     3704    // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app)
     3705    if (g.WantCaptureMouseNextFrame != -1)
     3706        g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
     3707    else
     3708        g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.OpenPopupStack.Size > 0);
     3709
     3710    // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app)
     3711    if (g.WantCaptureKeyboardNextFrame != -1)
     3712        g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
     3713    else
     3714        g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
     3715    if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
     3716        g.IO.WantCaptureKeyboard = true;
     3717
     3718    // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
     3719    g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
     3720}
     3721
     3722ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
     3723{
     3724    ImGuiContext& g = *GImGui;
     3725    ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None;
     3726    if (g.IO.KeyCtrl)   { key_mod_flags |= ImGuiKeyModFlags_Ctrl; }
     3727    if (g.IO.KeyShift)  { key_mod_flags |= ImGuiKeyModFlags_Shift; }
     3728    if (g.IO.KeyAlt)    { key_mod_flags |= ImGuiKeyModFlags_Alt; }
     3729    if (g.IO.KeySuper)  { key_mod_flags |= ImGuiKeyModFlags_Super; }
     3730    return key_mod_flags;
     3731}
     3732
     3733void ImGui::NewFrame()
     3734{
     3735    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
     3736    ImGuiContext& g = *GImGui;
     3737
     3738#ifdef IMGUI_ENABLE_TEST_ENGINE
     3739    ImGuiTestEngineHook_PreNewFrame(&g);
    30103740#endif
    30113741
    3012    if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad))
    3013       if (g.IO.NavInputs[ImGuiNavInput_Activate] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Input] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Cancel] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Menu] > 0.0f)
    3014          g.NavInputSource = ImGuiInputSource_NavGamepad;
    3015 
    3016    // Update Keyboard->Nav inputs mapping
    3017    if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
    3018    {
    3019 #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
    3020       NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate);
    3021       NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input);
    3022       NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel);
    3023       NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_);
    3024       NAV_MAP_KEY(ImGuiKey_RightArrow, ImGuiNavInput_KeyRight_);
    3025       NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_);
    3026       NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_);
    3027       if (g.IO.KeyCtrl)   g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
    3028       if (g.IO.KeyShift)  g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
    3029       if (g.IO.KeyAlt)    g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
    3030 #undef NAV_MAP_KEY
    3031    }
    3032 
    3033    memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration));
    3034    for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++)
    3035       g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
    3036 
    3037    // Process navigation init request (select first/default focus)
    3038    if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
    3039    {
    3040       // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
    3041       IM_ASSERT(g.NavWindow);
    3042       if (g.NavInitRequestFromMove)
    3043          SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
    3044       else
    3045          SetNavID(g.NavInitResultId, g.NavLayer);
    3046       g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
    3047    }
    3048    g.NavInitRequest = false;
    3049    g.NavInitRequestFromMove = false;
    3050    g.NavInitResultId = 0;
    3051    g.NavJustMovedToId = 0;
    3052 
    3053    // Process navigation move request
    3054    if (g.NavMoveRequest && (g.NavMoveResultLocal.ID != 0 || g.NavMoveResultOther.ID != 0))
    3055    {
    3056       // Select which result to use
    3057       ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
    3058       if (g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow) // Maybe entering a flattened child? In this case solve the tie using the regular scoring rules
    3059          if ((g.NavMoveResultOther.DistBox < g.NavMoveResultLocal.DistBox) || (g.NavMoveResultOther.DistBox == g.NavMoveResultLocal.DistBox && g.NavMoveResultOther.DistCenter < g.NavMoveResultLocal.DistCenter))
    3060             result = &g.NavMoveResultOther;
    3061 
    3062       IM_ASSERT(g.NavWindow && result->Window);
    3063 
    3064       // Scroll to keep newly navigated item fully into view
    3065       if (g.NavLayer == 0)
    3066          NavScrollToBringItemIntoView(result->Window, result->RectRel);
    3067 
    3068       // Apply result from previous frame navigation directional move request
    3069       ClearActiveID();
    3070       g.NavWindow = result->Window;
    3071       SetNavIDWithRectRel(result->ID, g.NavLayer, result->RectRel);
    3072       g.NavJustMovedToId = result->ID;
    3073       g.NavMoveFromClampedRefRect = false;
    3074    }
    3075 
    3076    // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
    3077    if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
    3078    {
    3079       IM_ASSERT(g.NavMoveRequest);
    3080       if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
    3081          g.NavDisableHighlight = false;
    3082       g.NavMoveRequestForward = ImGuiNavForward_None;
    3083    }
    3084 
    3085    // Apply application mouse position movement, after we had a chance to process move request result.
    3086    if (g.NavMousePosDirty && g.NavIdIsAlive)
    3087    {
    3088       // Set mouse position given our knowledge of the navigated item position from last frame
    3089       if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
    3090       {
    3091          IM_ASSERT(!g.NavDisableHighlight && g.NavDisableMouseHover);
    3092          g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos();
    3093          g.IO.WantSetMousePos = true;
    3094       }
    3095       g.NavMousePosDirty = false;
    3096    }
    3097    g.NavIdIsAlive = false;
    3098    g.NavJustTabbedId = 0;
    3099    IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
    3100 
    3101    // 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
    3102    if (g.NavWindow)
    3103       NavSaveLastChildNavWindow(g.NavWindow);
    3104    if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0)
    3105       g.NavWindow->NavLastChildNavWindow = NULL;
    3106 
    3107    NavUpdateWindowing();
    3108 
    3109    // Set output flags for user application
    3110    bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
    3111    bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
    3112    g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
    3113    g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL) || g.NavInitRequest;
    3114 
    3115    // Process NavCancel input (to close a popup, get back to parent, clear focus)
    3116    if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
    3117    {
    3118       if (g.ActiveId != 0)
    3119       {
    3120          ClearActiveID();
    3121       }
    3122       else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
    3123       {
    3124          // Exit child window
    3125          ImGuiWindow* child_window = g.NavWindow;
    3126          ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
    3127          IM_ASSERT(child_window->ChildId != 0);
    3128          FocusWindow(parent_window);
    3129          SetNavID(child_window->ChildId, 0);
    3130          g.NavIdIsAlive = false;
    3131          if (g.NavDisableMouseHover)
    3132             g.NavMousePosDirty = true;
    3133       }
    3134       else if (g.OpenPopupStack.Size > 0)
    3135       {
    3136          // Close open popup/menu
    3137          if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
    3138             ClosePopupToLevel(g.OpenPopupStack.Size - 1);
    3139       }
    3140       else if (g.NavLayer != 0)
    3141       {
    3142          // Leave the "menu" layer
    3143          NavRestoreLayer(0);
    3144       }
    3145       else
    3146       {
    3147          // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
    3148          if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
    3149             g.NavWindow->NavLastIds[0] = 0;
    3150          g.NavId = 0;
    3151       }
    3152    }
    3153 
    3154    // Process manual activation request
    3155    g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
    3156    if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
    3157    {
    3158       bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
    3159       bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
    3160       if (g.ActiveId == 0 && activate_pressed)
    3161          g.NavActivateId = g.NavId;
    3162       if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
    3163          g.NavActivateDownId = g.NavId;
    3164       if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
    3165          g.NavActivatePressedId = g.NavId;
    3166       if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
    3167          g.NavInputId = g.NavId;
    3168    }
    3169    if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
    3170       g.NavDisableHighlight = true;
    3171    if (g.NavActivateId != 0)
    3172       IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
    3173    g.NavMoveRequest = false;
    3174 
    3175    // Process programmatic activation request
    3176    if (g.NavNextActivateId != 0)
    3177       g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
    3178    g.NavNextActivateId = 0;
    3179 
    3180    // Initiate directional inputs request
    3181    const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags;
    3182    if (g.NavMoveRequestForward == ImGuiNavForward_None)
    3183    {
    3184       g.NavMoveDir = ImGuiDir_None;
    3185       if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
    3186       {
    3187          if ((allowed_dir_flags & (1 << ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left;
    3188          if ((allowed_dir_flags & (1 << ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight, ImGuiNavInput_KeyRight_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right;
    3189          if ((allowed_dir_flags & (1 << ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up;
    3190          if ((allowed_dir_flags & (1 << ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down;
    3191       }
    3192    }
    3193    else
    3194    {
    3195       // 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)
    3196       IM_ASSERT(g.NavMoveDir != ImGuiDir_None);
    3197       IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
    3198       g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
    3199    }
    3200 
    3201    if (g.NavMoveDir != ImGuiDir_None)
    3202    {
    3203       g.NavMoveRequest = true;
    3204       g.NavMoveDirLast = g.NavMoveDir;
    3205    }
    3206 
    3207    // 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
    3208    if (g.NavMoveRequest && g.NavId == 0)
    3209    {
    3210       g.NavInitRequest = g.NavInitRequestFromMove = true;
    3211       g.NavInitResultId = 0;
    3212       g.NavDisableHighlight = false;
    3213    }
    3214 
    3215    NavUpdateAnyRequestFlag();
    3216 
    3217    // Scrolling
    3218    if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
    3219    {
    3220       // *Fallback* manual-scroll with NavUp/NavDown when window has no navigable item
    3221       ImGuiWindow* window = g.NavWindow;
    3222       const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
    3223       if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
    3224       {
    3225          if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
    3226             SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
    3227          if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
    3228             SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
    3229       }
    3230 
    3231       // *Normal* Manual scroll with NavScrollXXX keys
    3232       // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
    3233       ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f);
    3234       if (scroll_dir.x != 0.0f && window->ScrollbarX)
    3235       {
    3236          SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
    3237          g.NavMoveFromClampedRefRect = true;
    3238       }
    3239       if (scroll_dir.y != 0.0f)
    3240       {
    3241          SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
    3242          g.NavMoveFromClampedRefRect = true;
    3243       }
    3244    }
    3245 
    3246    // Reset search results
    3247    g.NavMoveResultLocal.Clear();
    3248    g.NavMoveResultOther.Clear();
    3249 
    3250    // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
    3251    if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
    3252    {
    3253       ImGuiWindow* window = g.NavWindow;
    3254       ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
    3255       if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
    3256       {
    3257          float pad = window->CalcFontSize() * 0.5f;
    3258          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
    3259          window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel);
    3260          g.NavId = 0;
    3261       }
    3262       g.NavMoveFromClampedRefRect = false;
    3263    }
    3264 
    3265    // 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)
    3266    ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
    3267    g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect();
    3268    g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x);
    3269    g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x;
    3270    IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous fabsf() calls in NavScoreItem().
    3271                                                     //g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
    3272    g.NavScoringCount = 0;
    3273 #if IMGUI_DEBUG_NAV_RECTS
    3274    if (g.NavWindow) { for (int layer = 0; layer < 2; layer++) GetOverlayDrawList()->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG]
    3275    if (g.NavWindow) { ImU32 col = (g.NavWindow->HiddenFrames == 0) ? IM_COL32(255, 0, 255, 255) : IM_COL32(255, 0, 0, 255); ImVec2 p = NavCalcPreferredMousePos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); g.OverlayDrawList.AddCircleFilled(p, 3.0f, col); g.OverlayDrawList.AddText(NULL, 13.0f, p + ImVec2(8, -4), col, buf); }
     3742    // Check and assert for various common IO and Configuration mistakes
     3743    ErrorCheckNewFrameSanityChecks();
     3744
     3745    // Load settings on first frame, save settings when modified (after a delay)
     3746    UpdateSettings();
     3747
     3748    g.Time += g.IO.DeltaTime;
     3749    g.WithinFrameScope = true;
     3750    g.FrameCount += 1;
     3751    g.TooltipOverrideCount = 0;
     3752    g.WindowsActiveCount = 0;
     3753    g.MenusIdSubmittedThisFrame.resize(0);
     3754
     3755    // Calculate frame-rate for the user, as a purely luxurious feature
     3756    g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
     3757    g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
     3758    g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
     3759    g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
     3760
     3761    // Setup current font and draw list shared data
     3762    g.IO.Fonts->Locked = true;
     3763    SetCurrentFont(GetDefaultFont());
     3764    IM_ASSERT(g.Font->IsLoaded());
     3765    g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
     3766    g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
     3767    g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError);
     3768    g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
     3769    if (g.Style.AntiAliasedLines)
     3770        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
     3771    if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines))
     3772        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex;
     3773    if (g.Style.AntiAliasedFill)
     3774        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
     3775    if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
     3776        g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
     3777
     3778    g.BackgroundDrawList._ResetForNewFrame();
     3779    g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID);
     3780    g.BackgroundDrawList.PushClipRectFullScreen();
     3781
     3782    g.ForegroundDrawList._ResetForNewFrame();
     3783    g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID);
     3784    g.ForegroundDrawList.PushClipRectFullScreen();
     3785
     3786    // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
     3787    g.DrawData.Clear();
     3788
     3789    // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
     3790    if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
     3791        KeepAliveID(g.DragDropPayload.SourceId);
     3792
     3793    // Update HoveredId data
     3794    if (!g.HoveredIdPreviousFrame)
     3795        g.HoveredIdTimer = 0.0f;
     3796    if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
     3797        g.HoveredIdNotActiveTimer = 0.0f;
     3798    if (g.HoveredId)
     3799        g.HoveredIdTimer += g.IO.DeltaTime;
     3800    if (g.HoveredId && g.ActiveId != g.HoveredId)
     3801        g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
     3802    g.HoveredIdPreviousFrame = g.HoveredId;
     3803    g.HoveredId = 0;
     3804    g.HoveredIdAllowOverlap = false;
     3805    g.HoveredIdDisabled = false;
     3806
     3807    // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
     3808    if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
     3809        ClearActiveID();
     3810    if (g.ActiveId)
     3811        g.ActiveIdTimer += g.IO.DeltaTime;
     3812    g.LastActiveIdTimer += g.IO.DeltaTime;
     3813    g.ActiveIdPreviousFrame = g.ActiveId;
     3814    g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
     3815    g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
     3816    g.ActiveIdIsAlive = 0;
     3817    g.ActiveIdHasBeenEditedThisFrame = false;
     3818    g.ActiveIdPreviousFrameIsAlive = false;
     3819    g.ActiveIdIsJustActivated = false;
     3820    if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
     3821        g.TempInputId = 0;
     3822    if (g.ActiveId == 0)
     3823    {
     3824        g.ActiveIdUsingNavDirMask = 0x00;
     3825        g.ActiveIdUsingNavInputMask = 0x00;
     3826        g.ActiveIdUsingKeyInputMask = 0x00;
     3827    }
     3828
     3829    // Drag and drop
     3830    g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
     3831    g.DragDropAcceptIdCurr = 0;
     3832    g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
     3833    g.DragDropWithinSource = false;
     3834    g.DragDropWithinTarget = false;
     3835    g.DragDropHoldJustPressedId = 0;
     3836
     3837    // Update keyboard input state
     3838    // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools
     3839    g.IO.KeyMods = GetMergedKeyModFlags();
     3840    memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
     3841    for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
     3842        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;
     3843
     3844    // Update gamepad/keyboard navigation
     3845    NavUpdate();
     3846
     3847    // Update mouse input state
     3848    UpdateMouseInputs();
     3849
     3850    // Find hovered window
     3851    // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
     3852    UpdateHoveredWindowAndCaptureFlags();
     3853
     3854    // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
     3855    UpdateMouseMovingWindowNewFrame();
     3856
     3857    // Background darkening/whitening
     3858    if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
     3859        g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
     3860    else
     3861        g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
     3862
     3863    g.MouseCursor = ImGuiMouseCursor_Arrow;
     3864    g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
     3865    g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
     3866
     3867    // Mouse wheel scrolling, scale
     3868    UpdateMouseWheel();
     3869
     3870    // Update legacy TAB focus
     3871    UpdateTabFocus();
     3872
     3873    // Mark all windows as not visible and compact unused memory.
     3874    IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
     3875    const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX;
     3876    for (int i = 0; i != g.Windows.Size; i++)
     3877    {
     3878        ImGuiWindow* window = g.Windows[i];
     3879        window->WasActive = window->Active;
     3880        window->BeginCount = 0;
     3881        window->Active = false;
     3882        window->WriteAccessed = false;
     3883
     3884        // Garbage collect transient buffers of recently unused windows
     3885        if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
     3886            GcCompactTransientWindowBuffers(window);
     3887    }
     3888
     3889    // Closing the focused window restore focus to the first active root window in descending z-order
     3890    if (g.NavWindow && !g.NavWindow->WasActive)
     3891        FocusTopMostWindowUnderOne(NULL, NULL);
     3892
     3893    // No window should be open at the beginning of the frame.
     3894    // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
     3895    g.CurrentWindowStack.resize(0);
     3896    g.BeginPopupStack.resize(0);
     3897    ClosePopupsOverWindow(g.NavWindow, false);
     3898
     3899    // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
     3900    UpdateDebugToolItemPicker();
     3901
     3902    // Create implicit/fallback window - which we will only render it if the user has added something to it.
     3903    // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
     3904    // This fallback is particularly important as it avoid ImGui:: calls from crashing.
     3905    g.WithinFrameScopeWithImplicitWindow = true;
     3906    SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
     3907    Begin("Debug##Default");
     3908    IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true);
     3909
     3910#ifdef IMGUI_ENABLE_TEST_ENGINE
     3911    ImGuiTestEngineHook_PostNewFrame(&g);
    32763912#endif
    32773913}
    32783914
    3279 static void ImGui::UpdateMovingWindow()
    3280 {
    3281    ImGuiContext& g = *GImGui;
    3282    if (g.MovingWindow != NULL)
    3283    {
    3284       // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
    3285       // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
    3286       KeepAliveID(g.ActiveId);
    3287       IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);
    3288       ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
    3289       if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
    3290       {
    3291          ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
    3292          if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
    3293          {
    3294             MarkIniSettingsDirty(moving_window);
    3295             SetWindowPos(moving_window, pos, ImGuiCond_Always);
    3296          }
    3297          FocusWindow(g.MovingWindow);
    3298       }
    3299       else
    3300       {
    3301          ClearActiveID();
    3302          g.MovingWindow = NULL;
    3303       }
    3304    }
    3305    else
    3306    {
    3307       // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
    3308       if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
    3309       {
    3310          KeepAliveID(g.ActiveId);
    3311          if (!g.IO.MouseDown[0])
    3312             ClearActiveID();
    3313       }
    3314    }
    3315 }
    3316 
    3317 static void ImGui::UpdateMouseInputs()
    3318 {
    3319    ImGuiContext& g = *GImGui;
    3320 
    3321    // If mouse just appeared or disappeared (usually denoted by -FLT_MAX component, but in reality we test for -256000.0f) we cancel out movement in MouseDelta
    3322    if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
    3323       g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
    3324    else
    3325       g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
    3326    if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
    3327       g.NavDisableMouseHover = false;
    3328 
    3329    g.IO.MousePosPrev = g.IO.MousePos;
    3330    for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
    3331    {
    3332       g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
    3333       g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
    3334       g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
    3335       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;
    3336       g.IO.MouseDoubleClicked[i] = false;
    3337       if (g.IO.MouseClicked[i])
    3338       {
    3339          if (g.Time - g.IO.MouseClickedTime[i] < g.IO.MouseDoubleClickTime)
    3340          {
    3341             if (ImLengthSqr(g.IO.MousePos - g.IO.MouseClickedPos[i]) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
    3342                g.IO.MouseDoubleClicked[i] = true;
    3343             g.IO.MouseClickedTime[i] = -FLT_MAX;    // so the third click isn't turned into a double-click
    3344          }
    3345          else
    3346          {
    3347             g.IO.MouseClickedTime[i] = g.Time;
    3348          }
    3349          g.IO.MouseClickedPos[i] = g.IO.MousePos;
    3350          g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
    3351          g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
    3352       }
    3353       else if (g.IO.MouseDown[i])
    3354       {
    3355          ImVec2 mouse_delta = g.IO.MousePos - g.IO.MouseClickedPos[i];
    3356          g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, mouse_delta.x < 0.0f ? -mouse_delta.x : mouse_delta.x);
    3357          g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, mouse_delta.y < 0.0f ? -mouse_delta.y : mouse_delta.y);
    3358          g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(mouse_delta));
    3359       }
    3360       if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
    3361          g.NavDisableMouseHover = false;
    3362    }
    3363 }
    3364 
    3365 // 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)
    3366 void ImGui::NewFrameUpdateHoveredWindowAndCaptureFlags()
    3367 {
    3368    ImGuiContext& g = *GImGui;
    3369 
    3370    // Find the window hovered by mouse:
    3371    // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
    3372    // - 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.
    3373    // - 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.
    3374    g.HoveredWindow = (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoInputs)) ? g.MovingWindow : FindHoveredWindow();
    3375    g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
    3376 
    3377    // Modal windows prevents cursor from hovering behind them.
    3378    ImGuiWindow* modal_window = GetFrontMostPopupModal();
    3379    if (modal_window)
    3380       if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
    3381          g.HoveredRootWindow = g.HoveredWindow = NULL;
    3382 
    3383    // Disabled mouse?
    3384    if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
    3385       g.HoveredWindow = g.HoveredRootWindow = NULL;
    3386 
    3387    // 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.
    3388    int mouse_earliest_button_down = -1;
    3389    bool mouse_any_down = false;
    3390    for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
    3391    {
    3392       if (g.IO.MouseClicked[i])
    3393          g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty());
    3394       mouse_any_down |= g.IO.MouseDown[i];
    3395       if (g.IO.MouseDown[i])
    3396          if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
    3397             mouse_earliest_button_down = i;
    3398    }
    3399    const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
    3400 
    3401    // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
    3402    // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
    3403    const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
    3404    if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
    3405       g.HoveredWindow = g.HoveredRootWindow = NULL;
    3406 
    3407    // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app)
    3408    if (g.WantCaptureMouseNextFrame != -1)
    3409       g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
    3410    else
    3411       g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
    3412 
    3413    // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to imgui + app)
    3414    if (g.WantCaptureKeyboardNextFrame != -1)
    3415       g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
    3416    else
    3417       g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
    3418    if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
    3419       g.IO.WantCaptureKeyboard = true;
    3420 
    3421    // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
    3422    g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
    3423 }
    3424 
    3425 void ImGui::NewFrame()
    3426 {
    3427    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
    3428    ImGuiContext& g = *GImGui;
    3429 
    3430    // Check user data
    3431    // (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)
    3432    IM_ASSERT(g.Initialized);
    3433    IM_ASSERT(g.IO.DeltaTime >= 0.0f                                    && "Need a positive DeltaTime (zero is tolerated but will cause some timing issues)");
    3434    IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f  && "Invalid DisplaySize value");
    3435    IM_ASSERT(g.IO.Fonts->Fonts.Size > 0 && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
    3436    IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded() && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
    3437    IM_ASSERT(g.Style.CurveTessellationTol > 0.0f                       && "Invalid style setting");
    3438    IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f            && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)");
    3439    IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount) && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
    3440    for (int n = 0; n < ImGuiKey_COUNT; n++)
    3441       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)");
    3442 
    3443    // Perform simple check for required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP)
    3444    if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
    3445       IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
    3446 
    3447    // Load settings on first frame
    3448    if (!g.SettingsLoaded)
    3449    {
    3450       IM_ASSERT(g.SettingsWindows.empty());
    3451       LoadIniSettingsFromDisk(g.IO.IniFilename);
    3452       g.SettingsLoaded = true;
    3453    }
    3454 
    3455    // Save settings (with a delay so we don't spam disk too much)
    3456    if (g.SettingsDirtyTimer > 0.0f)
    3457    {
    3458       g.SettingsDirtyTimer -= g.IO.DeltaTime;
    3459       if (g.SettingsDirtyTimer <= 0.0f)
    3460          SaveIniSettingsToDisk(g.IO.IniFilename);
    3461    }
    3462 
    3463    g.Time += g.IO.DeltaTime;
    3464    g.FrameCount += 1;
    3465    g.TooltipOverrideCount = 0;
    3466    g.WindowsActiveCount = 0;
    3467 
    3468    SetCurrentFont(GetDefaultFont());
    3469    IM_ASSERT(g.Font->IsLoaded());
    3470    g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
    3471    g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
    3472 
    3473    g.OverlayDrawList.Clear();
    3474    g.OverlayDrawList.PushTextureID(g.IO.Fonts->TexID);
    3475    g.OverlayDrawList.PushClipRectFullScreen();
    3476    g.OverlayDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
    3477 
    3478    // Mark rendering data as invalid to prevent user who may have a handle on it to use it
    3479    g.DrawData.Clear();
    3480 
    3481    // Clear reference to active widget if the widget isn't alive anymore
    3482    if (!g.HoveredIdPreviousFrame)
    3483       g.HoveredIdTimer = 0.0f;
    3484    g.HoveredIdPreviousFrame = g.HoveredId;
    3485    g.HoveredId = 0;
    3486    g.HoveredIdAllowOverlap = false;
    3487    if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
    3488       ClearActiveID();
    3489    if (g.ActiveId)
    3490       g.ActiveIdTimer += g.IO.DeltaTime;
    3491    g.ActiveIdPreviousFrame = g.ActiveId;
    3492    g.ActiveIdIsAlive = false;
    3493    g.ActiveIdIsJustActivated = false;
    3494    if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId)
    3495       g.ScalarAsInputTextId = 0;
    3496 
    3497    // Elapse drag & drop payload
    3498    if (g.DragDropActive && g.DragDropPayload.DataFrameCount + 1 < g.FrameCount)
    3499    {
    3500       ClearDragDrop();
    3501       g.DragDropPayloadBufHeap.clear();
    3502       memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
    3503    }
    3504    g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
    3505    g.DragDropAcceptIdCurr = 0;
    3506    g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
    3507 
    3508    // Update keyboard input state
    3509    memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
    3510    for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
    3511       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;
    3512 
    3513    // Update gamepad/keyboard directional navigation
    3514    NavUpdate();
    3515 
    3516    // Update mouse input state
    3517    UpdateMouseInputs();
    3518 
    3519    // Calculate frame-rate for the user, as a purely luxurious feature
    3520    g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
    3521    g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
    3522    g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
    3523    g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
    3524 
    3525    // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
    3526    UpdateMovingWindow();
    3527    NewFrameUpdateHoveredWindowAndCaptureFlags();
    3528 
    3529    if (GetFrontMostPopupModal() != NULL)
    3530       g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f);
    3531    else
    3532       g.ModalWindowDarkeningRatio = 0.0f;
    3533 
    3534    g.MouseCursor = ImGuiMouseCursor_Arrow;
    3535    g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
    3536    g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
    3537 
    3538                                           // Mouse wheel scrolling, scale
    3539    if (g.HoveredWindow && !g.HoveredWindow->Collapsed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f))
    3540    {
    3541       // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set).
    3542       ImGuiWindow* window = g.HoveredWindow;
    3543       ImGuiWindow* scroll_window = window;
    3544       while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs) && scroll_window->ParentWindow)
    3545          scroll_window = scroll_window->ParentWindow;
    3546       const bool scroll_allowed = !(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoInputs);
    3547 
    3548       if (g.IO.MouseWheel != 0.0f)
    3549       {
    3550          if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
    3551          {
    3552             // Zoom / Scale window
    3553             const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
    3554             const float scale = new_font_scale / window->FontWindowScale;
    3555             window->FontWindowScale = new_font_scale;
    3556 
    3557             const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
    3558             window->Pos += offset;
    3559             window->Size *= scale;
    3560             window->SizeFull *= scale;
    3561          }
    3562          else if (!g.IO.KeyCtrl && scroll_allowed)
    3563          {
    3564             // Mouse wheel vertical scrolling
    3565             float scroll_amount = 5 * scroll_window->CalcFontSize();
    3566             scroll_amount = (float)(int)ImMin(scroll_amount, (scroll_window->ContentsRegionRect.GetHeight() + scroll_window->WindowPadding.y * 2.0f) * 0.67f);
    3567             SetWindowScrollY(scroll_window, scroll_window->Scroll.y - g.IO.MouseWheel * scroll_amount);
    3568          }
    3569       }
    3570       if (g.IO.MouseWheelH != 0.0f && scroll_allowed)
    3571       {
    3572          // Mouse wheel horizontal scrolling (for hardware that supports it)
    3573          float scroll_amount = scroll_window->CalcFontSize();
    3574          if (!g.IO.KeyCtrl && !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
    3575             SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheelH * scroll_amount);
    3576       }
    3577    }
    3578 
    3579    // Pressing TAB activate widget focus
    3580    if (g.ActiveId == 0 && g.NavWindow != NULL && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab, false))
    3581    {
    3582       if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
    3583          g.NavWindow->FocusIdxTabRequestNext = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
    3584       else
    3585          g.NavWindow->FocusIdxTabRequestNext = g.IO.KeyShift ? -1 : 0;
    3586    }
    3587    g.NavIdTabCounter = INT_MAX;
    3588 
    3589    // Mark all windows as not visible
    3590    for (int i = 0; i != g.Windows.Size; i++)
    3591    {
    3592       ImGuiWindow* window = g.Windows[i];
    3593       window->WasActive = window->Active;
    3594       window->Active = false;
    3595       window->WriteAccessed = false;
    3596    }
    3597 
    3598    // Closing the focused window restore focus to the first active root window in descending z-order
    3599    if (g.NavWindow && !g.NavWindow->WasActive)
    3600       FocusFrontMostActiveWindow(NULL);
    3601 
    3602    // No window should be open at the beginning of the frame.
    3603    // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
    3604    g.CurrentWindowStack.resize(0);
    3605    g.CurrentPopupStack.resize(0);
    3606    ClosePopupsOverWindow(g.NavWindow);
    3607 
    3608    // Create implicit window - we will only render it if the user has added something to it.
    3609    // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
    3610    SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
    3611    Begin("Debug##Default");
    3612 }
    3613 
    3614 static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
    3615 {
    3616    ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHash(name, 0));
    3617    if (!settings)
    3618       settings = AddWindowSettings(name);
    3619    return (void*)settings;
    3620 }
    3621 
    3622 static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
    3623 {
    3624    ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
    3625    float x, y;
    3626    int i;
    3627    if (sscanf(line, "Pos=%f,%f", &x, &y) == 2)         settings->Pos = ImVec2(x, y);
    3628    else if (sscanf(line, "Size=%f,%f", &x, &y) == 2)   settings->Size = ImMax(ImVec2(x, y), GImGui->Style.WindowMinSize);
    3629    else if (sscanf(line, "Collapsed=%d", &i) == 1)     settings->Collapsed = (i != 0);
    3630 }
    3631 
    3632 static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
    3633 {
    3634    // Gather data from windows that were active during this session
    3635    ImGuiContext& g = *imgui_ctx;
    3636    for (int i = 0; i != g.Windows.Size; i++)
    3637    {
    3638       ImGuiWindow* window = g.Windows[i];
    3639       if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
    3640          continue;
    3641       ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID);
    3642       if (!settings)
    3643          settings = AddWindowSettings(window->Name);
    3644       settings->Pos = window->Pos;
    3645       settings->Size = window->SizeFull;
    3646       settings->Collapsed = window->Collapsed;
    3647    }
    3648 
    3649    // Write a buffer
    3650    // If a window wasn't opened in this session we preserve its settings
    3651    buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve
    3652    for (int i = 0; i != g.SettingsWindows.Size; i++)
    3653    {
    3654       const ImGuiWindowSettings* settings = &g.SettingsWindows[i];
    3655       if (settings->Pos.x == FLT_MAX)
    3656          continue;
    3657       const char* name = settings->Name;
    3658       if (const char* p = strstr(name, "###"))  // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
    3659          name = p;
    3660       buf->appendf("[%s][%s]\n", handler->TypeName, name);
    3661       buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
    3662       buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
    3663       buf->appendf("Collapsed=%d\n", settings->Collapsed);
    3664       buf->appendf("\n");
    3665    }
     3915// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
     3916void ImGui::UpdateDebugToolItemPicker()
     3917{
     3918    ImGuiContext& g = *GImGui;
     3919    g.DebugItemPickerBreakId = 0;
     3920    if (g.DebugItemPickerActive)
     3921    {
     3922        const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
     3923        ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
     3924        if (ImGui::IsKeyPressedMap(ImGuiKey_Escape))
     3925            g.DebugItemPickerActive = false;
     3926        if (ImGui::IsMouseClicked(0) && hovered_id)
     3927        {
     3928            g.DebugItemPickerBreakId = hovered_id;
     3929            g.DebugItemPickerActive = false;
     3930        }
     3931        ImGui::SetNextWindowBgAlpha(0.60f);
     3932        ImGui::BeginTooltip();
     3933        ImGui::Text("HoveredId: 0x%08X", hovered_id);
     3934        ImGui::Text("Press ESC to abort picking.");
     3935        ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
     3936        ImGui::EndTooltip();
     3937    }
    36663938}
    36673939
    36683940void ImGui::Initialize(ImGuiContext* context)
    36693941{
    3670    ImGuiContext& g = *context;
    3671    IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
    3672    g.LogClipboard = IM_NEW(ImGuiTextBuffer)();
    3673 
    3674    // Add .ini handle for ImGuiWindow type
    3675    ImGuiSettingsHandler ini_handler;
    3676    ini_handler.TypeName = "Window";
    3677    ini_handler.TypeHash = ImHash("Window", 0, 0);
    3678    ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen;
    3679    ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine;
    3680    ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll;
    3681    g.SettingsHandlers.push_front(ini_handler);
    3682 
    3683    g.Initialized = true;
     3942    ImGuiContext& g = *context;
     3943    IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
     3944
     3945    // Add .ini handle for ImGuiWindow type
     3946    {
     3947        ImGuiSettingsHandler ini_handler;
     3948        ini_handler.TypeName = "Window";
     3949        ini_handler.TypeHash = ImHashStr("Window");
     3950        ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;
     3951        ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
     3952        ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
     3953        ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
     3954        ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
     3955        g.SettingsHandlers.push_back(ini_handler);
     3956    }
     3957
     3958#ifdef IMGUI_HAS_TABLE
     3959    // Add .ini handle for ImGuiTable type
     3960    {
     3961        ImGuiSettingsHandler ini_handler;
     3962        ini_handler.TypeName = "Table";
     3963        ini_handler.TypeHash = ImHashStr("Table");
     3964        ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen;
     3965        ini_handler.ReadLineFn = TableSettingsHandler_ReadLine;
     3966        ini_handler.WriteAllFn = TableSettingsHandler_WriteAll;
     3967        g.SettingsHandlers.push_back(ini_handler);
     3968    }
     3969#endif // #ifdef IMGUI_HAS_TABLE
     3970
     3971#ifdef IMGUI_HAS_DOCK
     3972#endif // #ifdef IMGUI_HAS_DOCK
     3973
     3974    g.Initialized = true;
    36843975}
    36853976
     
    36873978void ImGui::Shutdown(ImGuiContext* context)
    36883979{
    3689    ImGuiContext& g = *context;
    3690 
    3691    // 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)
    3692    if (g.IO.Fonts && g.FontAtlasOwnedByContext)
    3693       IM_DELETE(g.IO.Fonts);
    3694    g.IO.Fonts = NULL;
    3695 
    3696    // Cleanup of other data are conditional on actually having initialize ImGui.
    3697    if (!g.Initialized)
    3698       return;
    3699 
    3700    // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
    3701    if (g.SettingsLoaded)
    3702       SaveIniSettingsToDisk(g.IO.IniFilename);
    3703 
    3704    // Clear everything else
    3705    for (int i = 0; i < g.Windows.Size; i++)
    3706       IM_DELETE(g.Windows[i]);
    3707    g.Windows.clear();
    3708    g.WindowsSortBuffer.clear();
    3709    g.CurrentWindow = NULL;
    3710    g.CurrentWindowStack.clear();
    3711    g.WindowsById.Clear();
    3712    g.NavWindow = NULL;
    3713    g.HoveredWindow = NULL;
    3714    g.HoveredRootWindow = NULL;
    3715    g.ActiveIdWindow = NULL;
    3716    g.MovingWindow = NULL;
    3717    g.ColorModifiers.clear();
    3718    g.StyleModifiers.clear();
    3719    g.FontStack.clear();
    3720    g.OpenPopupStack.clear();
    3721    g.CurrentPopupStack.clear();
    3722    g.DrawDataBuilder.ClearFreeMemory();
    3723    g.OverlayDrawList.ClearFreeMemory();
    3724    g.PrivateClipboard.clear();
    3725    g.InputTextState.Text.clear();
    3726    g.InputTextState.InitialText.clear();
    3727    g.InputTextState.TempTextBuffer.clear();
    3728 
    3729    for (int i = 0; i < g.SettingsWindows.Size; i++)
    3730       IM_DELETE(g.SettingsWindows[i].Name);
    3731    g.SettingsWindows.clear();
    3732    g.SettingsHandlers.clear();
    3733 
    3734    if (g.LogFile && g.LogFile != stdout)
    3735    {
    3736       fclose(g.LogFile);
    3737       g.LogFile = NULL;
    3738    }
    3739    if (g.LogClipboard)
    3740       IM_DELETE(g.LogClipboard);
    3741    g.LogClipboard = NULL;
    3742 
    3743    g.Initialized = false;
    3744 }
    3745 
    3746 ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
    3747 {
    3748    ImGuiContext& g = *GImGui;
    3749    for (int i = 0; i != g.SettingsWindows.Size; i++)
    3750       if (g.SettingsWindows[i].Id == id)
    3751          return &g.SettingsWindows[i];
    3752    return NULL;
    3753 }
    3754 
    3755 static ImGuiWindowSettings* AddWindowSettings(const char* name)
    3756 {
    3757    ImGuiContext& g = *GImGui;
    3758    g.SettingsWindows.push_back(ImGuiWindowSettings());
    3759    ImGuiWindowSettings* settings = &g.SettingsWindows.back();
    3760    settings->Name = ImStrdup(name);
    3761    settings->Id = ImHash(name, 0);
    3762    return settings;
    3763 }
    3764 
    3765 static void LoadIniSettingsFromDisk(const char* ini_filename)
    3766 {
    3767    if (!ini_filename)
    3768       return;
    3769    char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", NULL, +1);
    3770    if (!file_data)
    3771       return;
    3772    LoadIniSettingsFromMemory(file_data);
    3773    ImGui::MemFree(file_data);
    3774 }
    3775 
    3776 ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
    3777 {
    3778    ImGuiContext& g = *GImGui;
    3779    const ImGuiID type_hash = ImHash(type_name, 0, 0);
    3780    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
    3781       if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
    3782          return &g.SettingsHandlers[handler_n];
    3783    return NULL;
    3784 }
    3785 
    3786 // Zero-tolerance, no error reporting, cheap .ini parsing
    3787 static void LoadIniSettingsFromMemory(const char* buf_readonly)
    3788 {
    3789    // For convenience and to make the code simpler, we'll write zero terminators inside the buffer. So let's create a writable copy.
    3790    char* buf = ImStrdup(buf_readonly);
    3791    char* buf_end = buf + strlen(buf);
    3792 
    3793    ImGuiContext& g = *GImGui;
    3794    void* entry_data = NULL;
    3795    ImGuiSettingsHandler* entry_handler = NULL;
    3796 
    3797    char* line_end = NULL;
    3798    for (char* line = buf; line < buf_end; line = line_end + 1)
    3799    {
    3800       // Skip new lines markers, then find end of the line
    3801       while (*line == '\n' || *line == '\r')
    3802          line++;
    3803       line_end = line;
    3804       while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
    3805          line_end++;
    3806       line_end[0] = 0;
    3807 
    3808       if (line[0] == '[' && line_end > line && line_end[-1] == ']')
    3809       {
    3810          // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
    3811          line_end[-1] = 0;
    3812          const char* name_end = line_end - 1;
    3813          const char* type_start = line + 1;
    3814          char* type_end = (char*)(intptr_t)ImStrchrRange(type_start, name_end, ']');
    3815          const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
    3816          if (!type_end || !name_start)
    3817          {
    3818             name_start = type_start; // Import legacy entries that have no type
    3819             type_start = "Window";
    3820          }
    3821          else
    3822          {
    3823             *type_end = 0; // Overwrite first ']'
    3824             name_start++;  // Skip second '['
    3825          }
    3826          entry_handler = ImGui::FindSettingsHandler(type_start);
    3827          entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
    3828       }
    3829       else if (entry_handler != NULL && entry_data != NULL)
    3830       {
    3831          // Let type handler parse the line
    3832          entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
    3833       }
    3834    }
    3835    ImGui::MemFree(buf);
    3836    g.SettingsLoaded = true;
    3837 }
    3838 
    3839 static void SaveIniSettingsToDisk(const char* ini_filename)
    3840 {
    3841    ImGuiContext& g = *GImGui;
    3842    g.SettingsDirtyTimer = 0.0f;
    3843    if (!ini_filename)
    3844       return;
    3845 
    3846    ImVector<char> buf;
    3847    SaveIniSettingsToMemory(buf);
    3848 
    3849    FILE* f = ImFileOpen(ini_filename, "wt");
    3850    if (!f)
    3851       return;
    3852    fwrite(buf.Data, sizeof(char), (size_t)buf.Size, f);
    3853    fclose(f);
    3854 }
    3855 
    3856 static void SaveIniSettingsToMemory(ImVector<char>& out_buf)
    3857 {
    3858    ImGuiContext& g = *GImGui;
    3859    g.SettingsDirtyTimer = 0.0f;
    3860 
    3861    ImGuiTextBuffer buf;
    3862    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
    3863    {
    3864       ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
    3865       handler->WriteAllFn(&g, handler, &buf);
    3866    }
    3867 
    3868    buf.Buf.pop_back(); // Remove extra zero-terminator used by ImGuiTextBuffer
    3869    out_buf.swap(buf.Buf);
    3870 }
    3871 
    3872 void ImGui::MarkIniSettingsDirty()
    3873 {
    3874    ImGuiContext& g = *GImGui;
    3875    if (g.SettingsDirtyTimer <= 0.0f)
    3876       g.SettingsDirtyTimer = g.IO.IniSavingRate;
    3877 }
    3878 
    3879 static void MarkIniSettingsDirty(ImGuiWindow* window)
    3880 {
    3881    ImGuiContext& g = *GImGui;
    3882    if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
    3883       if (g.SettingsDirtyTimer <= 0.0f)
    3884          g.SettingsDirtyTimer = g.IO.IniSavingRate;
     3980    // 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)
     3981    ImGuiContext& g = *context;
     3982    if (g.IO.Fonts && g.FontAtlasOwnedByContext)
     3983    {
     3984        g.IO.Fonts->Locked = false;
     3985        IM_DELETE(g.IO.Fonts);
     3986    }
     3987    g.IO.Fonts = NULL;
     3988
     3989    // Cleanup of other data are conditional on actually having initialized Dear ImGui.
     3990    if (!g.Initialized)
     3991        return;
     3992
     3993    // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
     3994    if (g.SettingsLoaded && g.IO.IniFilename != NULL)
     3995    {
     3996        ImGuiContext* backup_context = GImGui;
     3997        SetCurrentContext(context);
     3998        SaveIniSettingsToDisk(g.IO.IniFilename);
     3999        SetCurrentContext(backup_context);
     4000    }
     4001
     4002    // Notify hooked test engine, if any
     4003#ifdef IMGUI_ENABLE_TEST_ENGINE
     4004    ImGuiTestEngineHook_Shutdown(context);
     4005#endif
     4006
     4007    // Clear everything else
     4008    for (int i = 0; i < g.Windows.Size; i++)
     4009        IM_DELETE(g.Windows[i]);
     4010    g.Windows.clear();
     4011    g.WindowsFocusOrder.clear();
     4012    g.WindowsTempSortBuffer.clear();
     4013    g.CurrentWindow = NULL;
     4014    g.CurrentWindowStack.clear();
     4015    g.WindowsById.Clear();
     4016    g.NavWindow = NULL;
     4017    g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
     4018    g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;
     4019    g.MovingWindow = NULL;
     4020    g.ColorModifiers.clear();
     4021    g.StyleModifiers.clear();
     4022    g.FontStack.clear();
     4023    g.OpenPopupStack.clear();
     4024    g.BeginPopupStack.clear();
     4025    g.DrawDataBuilder.ClearFreeMemory();
     4026    g.BackgroundDrawList._ClearFreeMemory();
     4027    g.ForegroundDrawList._ClearFreeMemory();
     4028
     4029    g.TabBars.Clear();
     4030    g.CurrentTabBarStack.clear();
     4031    g.ShrinkWidthBuffer.clear();
     4032
     4033    g.ClipboardHandlerData.clear();
     4034    g.MenusIdSubmittedThisFrame.clear();
     4035    g.InputTextState.ClearFreeMemory();
     4036
     4037    g.SettingsWindows.clear();
     4038    g.SettingsHandlers.clear();
     4039
     4040    if (g.LogFile)
     4041    {
     4042#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
     4043        if (g.LogFile != stdout)
     4044#endif
     4045            ImFileClose(g.LogFile);
     4046        g.LogFile = NULL;
     4047    }
     4048    g.LogBuffer.clear();
     4049
     4050    g.Initialized = false;
    38854051}
    38864052
     
    38884054static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
    38894055{
    3890    const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
    3891    const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
    3892    if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
    3893       return d;
    3894    if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
    3895       return d;
    3896    return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
    3897 }
    3898 
    3899 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
    3900 {
    3901    out_sorted_windows->push_back(window);
    3902    if (window->Active)
    3903    {
    3904       int count = window->DC.ChildWindows.Size;
    3905       if (count > 1)
    3906          qsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
    3907       for (int i = 0; i < count; i++)
    3908       {
    3909          ImGuiWindow* child = window->DC.ChildWindows[i];
    3910          if (child->Active)
    3911             AddWindowToSortedBuffer(out_sorted_windows, child);
    3912       }
    3913    }
     4056    const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
     4057    const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
     4058    if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
     4059        return d;
     4060    if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
     4061        return d;
     4062    return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
     4063}
     4064
     4065static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
     4066{
     4067    out_sorted_windows->push_back(window);
     4068    if (window->Active)
     4069    {
     4070        int count = window->DC.ChildWindows.Size;
     4071        if (count > 1)
     4072            ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
     4073        for (int i = 0; i < count; i++)
     4074        {
     4075            ImGuiWindow* child = window->DC.ChildWindows[i];
     4076            if (child->Active)
     4077                AddWindowToSortBuffer(out_sorted_windows, child);
     4078        }
     4079    }
    39144080}
    39154081
    39164082static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
    39174083{
    3918    if (draw_list->CmdBuffer.empty())
    3919       return;
    3920 
    3921    // Remove trailing command if unused
    3922    ImDrawCmd& last_cmd = draw_list->CmdBuffer.back();
    3923    if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL)
    3924    {
    3925       draw_list->CmdBuffer.pop_back();
    3926       if (draw_list->CmdBuffer.empty())
    3927          return;
    3928    }
    3929 
    3930    // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. May trigger for you if you are using PrimXXX functions incorrectly.
    3931    IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
    3932    IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
    3933    IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
    3934 
    3935    // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
    3936    // If this assert triggers because you are drawing lots of stuff manually:
    3937    // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use the Metrics window to inspect draw list contents.
    3938    // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes.
    3939    //    You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing:
    3940    //      glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
    3941    //    Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API.
    3942    // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists.
    3943    if (sizeof(ImDrawIdx) == 2)
    3944       IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
    3945 
    3946    out_list->push_back(draw_list);
     4084    // Remove trailing command if unused.
     4085    // Technically we could return directly instead of popping, but this make things looks neat in Metrics window as well.
     4086    draw_list->_PopUnusedDrawCmd();
     4087    if (draw_list->CmdBuffer.Size == 0)
     4088        return;
     4089
     4090    // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
     4091    // May trigger for you if you are using PrimXXX functions incorrectly.
     4092    IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
     4093    IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
     4094    if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
     4095        IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
     4096
     4097    // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
     4098    // If this assert triggers because you are drawing lots of stuff manually:
     4099    // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
     4100    //   Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents.
     4101    // - If you want large meshes with more than 64K vertices, you can either:
     4102    //   (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
     4103    //       Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't.
     4104    //       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.
     4105    //   (B) Or handle 32-bit indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
     4106    //       Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time:
     4107    //         glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
     4108    //       Your own engine or render API may use different parameters or function calls to specify index sizes.
     4109    //       2 and 4 bytes indices are generally supported by most graphics API.
     4110    // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
     4111    //   the 64K limit to split your draw commands in multiple draw lists.
     4112    if (sizeof(ImDrawIdx) == 2)
     4113        IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
     4114
     4115    out_list->push_back(draw_list);
    39474116}
    39484117
    39494118static void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window)
    39504119{
    3951    AddDrawListToDrawData(out_render_list, window->DrawList);
    3952    for (int i = 0; i < window->DC.ChildWindows.Size; i++)
    3953    {
    3954       ImGuiWindow* child = window->DC.ChildWindows[i];
    3955       if (child->Active && child->HiddenFrames == 0) // clipped children may have been marked not active
    3956          AddWindowToDrawData(out_render_list, child);
    3957    }
    3958 }
    3959 
    3960 static void AddWindowToDrawDataSelectLayer(ImGuiWindow* window)
    3961 {
    3962    ImGuiContext& g = *GImGui;
    3963    g.IO.MetricsActiveWindows++;
    3964    if (window->Flags & ImGuiWindowFlags_Tooltip)
    3965       AddWindowToDrawData(&g.DrawDataBuilder.Layers[1], window);
    3966    else
    3967       AddWindowToDrawData(&g.DrawDataBuilder.Layers[0], window);
     4120    ImGuiContext& g = *GImGui;
     4121    g.IO.MetricsRenderWindows++;
     4122    AddDrawListToDrawData(out_render_list, window->DrawList);
     4123    for (int i = 0; i < window->DC.ChildWindows.Size; i++)
     4124    {
     4125        ImGuiWindow* child = window->DC.ChildWindows[i];
     4126        if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active
     4127            AddWindowToDrawData(out_render_list, child);
     4128    }
     4129}
     4130
     4131// Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu)
     4132static void AddRootWindowToDrawData(ImGuiWindow* window)
     4133{
     4134    ImGuiContext& g = *GImGui;
     4135    int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;
     4136    AddWindowToDrawData(&g.DrawDataBuilder.Layers[layer], window);
    39684137}
    39694138
    39704139void ImDrawDataBuilder::FlattenIntoSingleLayer()
    39714140{
    3972    int n = Layers[0].Size;
    3973    int size = n;
    3974    for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
    3975       size += Layers[i].Size;
    3976    Layers[0].resize(size);
    3977    for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
    3978    {
    3979       ImVector<ImDrawList*>& layer = Layers[layer_n];
    3980       if (layer.empty())
    3981          continue;
    3982       memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
    3983       n += layer.Size;
    3984       layer.resize(0);
    3985    }
    3986 }
    3987 
    3988 static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* out_draw_data)
    3989 {
    3990    out_draw_data->Valid = true;
    3991    out_draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
    3992    out_draw_data->CmdListsCount = draw_lists->Size;
    3993    out_draw_data->TotalVtxCount = out_draw_data->TotalIdxCount = 0;
    3994    for (int n = 0; n < draw_lists->Size; n++)
    3995    {
    3996       out_draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
    3997       out_draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
    3998    }
    3999 }
    4000 
    4001 // When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result.
     4141    int n = Layers[0].Size;
     4142    int size = n;
     4143    for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
     4144        size += Layers[i].Size;
     4145    Layers[0].resize(size);
     4146    for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
     4147    {
     4148        ImVector<ImDrawList*>& layer = Layers[layer_n];
     4149        if (layer.empty())
     4150            continue;
     4151        memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
     4152        n += layer.Size;
     4153        layer.resize(0);
     4154    }
     4155}
     4156
     4157static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* draw_data)
     4158{
     4159    ImGuiIO& io = ImGui::GetIO();
     4160    draw_data->Valid = true;
     4161    draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
     4162    draw_data->CmdListsCount = draw_lists->Size;
     4163    draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
     4164    draw_data->DisplayPos = ImVec2(0.0f, 0.0f);
     4165    draw_data->DisplaySize = io.DisplaySize;
     4166    draw_data->FramebufferScale = io.DisplayFramebufferScale;
     4167    for (int n = 0; n < draw_lists->Size; n++)
     4168    {
     4169        draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
     4170        draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
     4171    }
     4172}
     4173
     4174// Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering.
     4175// - When using this function it is sane to ensure that float are perfectly rounded to integer values,
     4176//   so that e.g. (int)(max.x-min.x) in user's render produce correct result.
     4177// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect():
     4178//   some frequently called functions which to modify both channels and clipping simultaneously tend to use the
     4179//   more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds.
    40024180void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
    40034181{
    4004    ImGuiWindow* window = GetCurrentWindow();
    4005    window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
    4006    window->ClipRect = window->DrawList->_ClipRectStack.back();
     4182    ImGuiWindow* window = GetCurrentWindow();
     4183    window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
     4184    window->ClipRect = window->DrawList->_ClipRectStack.back();
    40074185}
    40084186
    40094187void ImGui::PopClipRect()
    40104188{
    4011    ImGuiWindow* window = GetCurrentWindow();
    4012    window->DrawList->PopClipRect();
    4013    window->ClipRect = window->DrawList->_ClipRectStack.back();
     4189    ImGuiWindow* window = GetCurrentWindow();
     4190    window->DrawList->PopClipRect();
     4191    window->ClipRect = window->DrawList->_ClipRectStack.back();
    40144192}
    40154193
     
    40174195void ImGui::EndFrame()
    40184196{
    4019    ImGuiContext& g = *GImGui;
    4020    IM_ASSERT(g.Initialized);                       // Forgot to call ImGui::NewFrame()
    4021    if (g.FrameCountEnded == g.FrameCount)          // Don't process EndFrame() multiple times.
    4022       return;
    4023 
    4024    // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
    4025    if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f)
    4026    {
    4027       g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y);
    4028       g.PlatformImeLastPos = g.PlatformImePos;
    4029    }
    4030 
    4031    // Hide implicit "Debug" window if it hasn't been used
    4032    IM_ASSERT(g.CurrentWindowStack.Size == 1);    // Mismatched Begin()/End() calls
    4033    if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
    4034       g.CurrentWindow->Active = false;
    4035    End();
    4036 
    4037    if (g.ActiveId == 0 && g.HoveredId == 0)
    4038    {
    4039       if (!g.NavWindow || !g.NavWindow->Appearing) // Unless we just made a window/popup appear
    4040       {
    4041          // Click to focus window and start moving (after we're done with all our widgets)
    4042          if (g.IO.MouseClicked[0])
    4043          {
    4044             if (g.HoveredRootWindow != NULL)
    4045             {
    4046                // Set ActiveId even if the _NoMove flag is set, without it dragging away from a window with _NoMove would activate hover on other windows.
    4047                FocusWindow(g.HoveredWindow);
    4048                SetActiveID(g.HoveredWindow->MoveId, g.HoveredWindow);
    4049                g.NavDisableHighlight = true;
    4050                g.ActiveIdClickOffset = g.IO.MousePos - g.HoveredRootWindow->Pos;
    4051                if (!(g.HoveredWindow->Flags & ImGuiWindowFlags_NoMove) && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoMove))
    4052                   g.MovingWindow = g.HoveredWindow;
    4053             }
    4054             else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL)
    4055             {
    4056                // Clicking on void disable focus
    4057                FocusWindow(NULL);
    4058             }
    4059          }
    4060 
    4061          // With right mouse button we close popups without changing focus
    4062          // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger)
    4063          if (g.IO.MouseClicked[1])
    4064          {
    4065             // Find the top-most window between HoveredWindow and the front most Modal Window.
    4066             // This is where we can trim the popup stack.
    4067             ImGuiWindow* modal = GetFrontMostPopupModal();
    4068             bool hovered_window_above_modal = false;
    4069             if (modal == NULL)
    4070                hovered_window_above_modal = true;
    4071             for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
    4072             {
    4073                ImGuiWindow* window = g.Windows[i];
    4074                if (window == modal)
    4075                   break;
    4076                if (window == g.HoveredWindow)
    4077                   hovered_window_above_modal = true;
    4078             }
    4079             ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal);
    4080          }
    4081       }
    4082    }
    4083 
    4084    // Sort the window list so that all child windows are after their parent
    4085    // We cannot do that on FocusWindow() because childs may not exist yet
    4086    g.WindowsSortBuffer.resize(0);
    4087    g.WindowsSortBuffer.reserve(g.Windows.Size);
    4088    for (int i = 0; i != g.Windows.Size; i++)
    4089    {
    4090       ImGuiWindow* window = g.Windows[i];
    4091       if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow))       // if a child is active its parent will add it
    4092          continue;
    4093       AddWindowToSortedBuffer(&g.WindowsSortBuffer, window);
    4094    }
    4095 
    4096    IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size);  // we done something wrong
    4097    g.Windows.swap(g.WindowsSortBuffer);
    4098 
    4099    // Clear Input data for next frame
    4100    g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
    4101    memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
    4102    memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
    4103 
    4104    g.FrameCountEnded = g.FrameCount;
     4197    ImGuiContext& g = *GImGui;
     4198    IM_ASSERT(g.Initialized);
     4199
     4200    // Don't process EndFrame() multiple times.
     4201    if (g.FrameCountEnded == g.FrameCount)
     4202        return;
     4203    IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
     4204
     4205    ErrorCheckEndFrameSanityChecks();
     4206
     4207    // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
     4208    if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f))
     4209    {
     4210        g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y);
     4211        g.PlatformImeLastPos = g.PlatformImePos;
     4212    }
     4213
     4214    // Hide implicit/fallback "Debug" window if it hasn't been used
     4215    g.WithinFrameScopeWithImplicitWindow = false;
     4216    if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
     4217        g.CurrentWindow->Active = false;
     4218    End();
     4219
     4220    // Update navigation: CTRL+Tab, wrap-around requests
     4221    NavEndFrame();
     4222
     4223    // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
     4224    if (g.DragDropActive)
     4225    {
     4226        bool is_delivered = g.DragDropPayload.Delivery;
     4227        bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));
     4228        if (is_delivered || is_elapsed)
     4229            ClearDragDrop();
     4230    }
     4231
     4232    // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.
     4233    if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
     4234    {
     4235        g.DragDropWithinSource = true;
     4236        SetTooltip("...");
     4237        g.DragDropWithinSource = false;
     4238    }
     4239
     4240    // End frame
     4241    g.WithinFrameScope = false;
     4242    g.FrameCountEnded = g.FrameCount;
     4243
     4244    // Initiate moving window + handle left-click and right-click focus
     4245    UpdateMouseMovingWindowEndFrame();
     4246
     4247    // Sort the window list so that all child windows are after their parent
     4248    // We cannot do that on FocusWindow() because children may not exist yet
     4249    g.WindowsTempSortBuffer.resize(0);
     4250    g.WindowsTempSortBuffer.reserve(g.Windows.Size);
     4251    for (int i = 0; i != g.Windows.Size; i++)
     4252    {
     4253        ImGuiWindow* window = g.Windows[i];
     4254        if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow))       // if a child is active its parent will add it
     4255            continue;
     4256        AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);
     4257    }
     4258
     4259    // 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.
     4260    IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size);
     4261    g.Windows.swap(g.WindowsTempSortBuffer);
     4262    g.IO.MetricsActiveWindows = g.WindowsActiveCount;
     4263
     4264    // Unlock font atlas
     4265    g.IO.Fonts->Locked = false;
     4266
     4267    // Clear Input data for next frame
     4268    g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
     4269    g.IO.InputQueueCharacters.resize(0);
     4270    memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
    41054271}
    41064272
    41074273void ImGui::Render()
    41084274{
    4109    ImGuiContext& g = *GImGui;
    4110    IM_ASSERT(g.Initialized);   // Forgot to call ImGui::NewFrame()
    4111 
    4112    if (g.FrameCountEnded != g.FrameCount)
    4113       ImGui::EndFrame();
    4114    g.FrameCountRendered = g.FrameCount;
    4115 
    4116    // Gather windows to render
    4117    g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsActiveWindows = 0;
    4118    g.DrawDataBuilder.Clear();
    4119    ImGuiWindow* window_to_render_front_most = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget : NULL;
    4120    for (int n = 0; n != g.Windows.Size; n++)
    4121    {
    4122       ImGuiWindow* window = g.Windows[n];
    4123       if (window->Active && window->HiddenFrames == 0 && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != window_to_render_front_most)
    4124          AddWindowToDrawDataSelectLayer(window);
    4125    }
    4126    if (window_to_render_front_most && window_to_render_front_most->Active && window_to_render_front_most->HiddenFrames == 0) // NavWindowingTarget is always temporarily displayed as the front-most window
    4127       AddWindowToDrawDataSelectLayer(window_to_render_front_most);
    4128    g.DrawDataBuilder.FlattenIntoSingleLayer();
    4129 
    4130    // Draw software mouse cursor if requested
    4131    ImVec2 offset, size, uv[4];
    4132    if (g.IO.MouseDrawCursor && g.IO.Fonts->GetMouseCursorTexData(g.MouseCursor, &offset, &size, &uv[0], &uv[2]))
    4133    {
    4134       const ImVec2 pos = g.IO.MousePos - offset;
    4135       const ImTextureID tex_id = g.IO.Fonts->TexID;
    4136       const float sc = g.Style.MouseCursorScale;
    4137       g.OverlayDrawList.PushTextureID(tex_id);
    4138       g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(1, 0)*sc, pos + ImVec2(1, 0)*sc + size * sc, uv[2], uv[3], IM_COL32(0, 0, 0, 48));        // Shadow
    4139       g.OverlayDrawList.AddImage(tex_id, pos + ImVec2(2, 0)*sc, pos + ImVec2(2, 0)*sc + size * sc, uv[2], uv[3], IM_COL32(0, 0, 0, 48));        // Shadow
    4140       g.OverlayDrawList.AddImage(tex_id, pos, pos + size * sc, uv[2], uv[3], IM_COL32(0, 0, 0, 255));       // Black border
    4141       g.OverlayDrawList.AddImage(tex_id, pos, pos + size * sc, uv[0], uv[1], IM_COL32(255, 255, 255, 255)); // White fill
    4142       g.OverlayDrawList.PopTextureID();
    4143    }
    4144    if (!g.OverlayDrawList.VtxBuffer.empty())
    4145       AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.OverlayDrawList);
    4146 
    4147    // Setup ImDrawData structure for end-user
    4148    SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData);
    4149    g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount;
    4150    g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount;
    4151 
    4152    // Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData()
     4275    ImGuiContext& g = *GImGui;
     4276    IM_ASSERT(g.Initialized);
     4277
     4278    if (g.FrameCountEnded != g.FrameCount)
     4279        EndFrame();
     4280    g.FrameCountRendered = g.FrameCount;
     4281    g.IO.MetricsRenderWindows = 0;
     4282    g.DrawDataBuilder.Clear();
     4283
     4284    // Add background ImDrawList
     4285    if (!g.BackgroundDrawList.VtxBuffer.empty())
     4286        AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList);
     4287
     4288    // Add ImDrawList to render
     4289    ImGuiWindow* windows_to_render_top_most[2];
     4290    windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
     4291    windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);
     4292    for (int n = 0; n != g.Windows.Size; n++)
     4293    {
     4294        ImGuiWindow* window = g.Windows[n];
     4295        if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
     4296            AddRootWindowToDrawData(window);
     4297    }
     4298    for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
     4299        if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
     4300            AddRootWindowToDrawData(windows_to_render_top_most[n]);
     4301    g.DrawDataBuilder.FlattenIntoSingleLayer();
     4302
     4303    // Draw software mouse cursor if requested
     4304    if (g.IO.MouseDrawCursor)
     4305        RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
     4306
     4307    // Add foreground ImDrawList
     4308    if (!g.ForegroundDrawList.VtxBuffer.empty())
     4309        AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList);
     4310
     4311    // Setup ImDrawData structure for end-user
     4312    SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData);
     4313    g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount;
     4314    g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount;
     4315
     4316    // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves.
    41534317#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    4154    if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
    4155       g.IO.RenderDrawListsFn(&g.DrawData);
     4318    if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
     4319        g.IO.RenderDrawListsFn(&g.DrawData);
    41564320#endif
    41574321}
    41584322
    4159 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
    4160 {
    4161    const char* text_display_end = text;
    4162    if (!text_end)
    4163       text_end = (const char*)-1;
    4164 
    4165    while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
    4166       text_display_end++;
    4167    return text_display_end;
    4168 }
    4169 
    4170 // Pass text data straight to log (without being displayed)
    4171 void ImGui::LogText(const char* fmt, ...)
    4172 {
    4173    ImGuiContext& g = *GImGui;
    4174    if (!g.LogEnabled)
    4175       return;
    4176 
    4177    va_list args;
    4178    va_start(args, fmt);
    4179    if (g.LogFile)
    4180       vfprintf(g.LogFile, fmt, args);
    4181    else
    4182       g.LogClipboard->appendfv(fmt, args);
    4183    va_end(args);
    4184 }
    4185 
    4186 // Internal version that takes a position to decide on newline placement and pad items according to their depth.
    4187 // We split text into individual lines to add current tree level padding
    4188 static void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL)
    4189 {
    4190    ImGuiContext& g = *GImGui;
    4191    ImGuiWindow* window = g.CurrentWindow;
    4192 
    4193    if (!text_end)
    4194       text_end = ImGui::FindRenderedTextEnd(text, text_end);
    4195 
    4196    const bool log_new_line = ref_pos && (ref_pos->y > window->DC.LogLinePosY + 1);
    4197    if (ref_pos)
    4198       window->DC.LogLinePosY = ref_pos->y;
    4199 
    4200    const char* text_remaining = text;
    4201    if (g.LogStartDepth > window->DC.TreeDepth)  // Re-adjust padding if we have popped out of our starting depth
    4202       g.LogStartDepth = window->DC.TreeDepth;
    4203    const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth);
    4204    for (;;)
    4205    {
    4206       // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
    4207       const char* line_end = text_remaining;
    4208       while (line_end < text_end)
    4209          if (*line_end == '\n')
     4323// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
     4324// CalcTextSize("") should return ImVec2(0.0f, g.FontSize)
     4325ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
     4326{
     4327    ImGuiContext& g = *GImGui;
     4328
     4329    const char* text_display_end;
     4330    if (hide_text_after_double_hash)
     4331        text_display_end = FindRenderedTextEnd(text, text_end);      // Hide anything after a '##' string
     4332    else
     4333        text_display_end = text_end;
     4334
     4335    ImFont* font = g.Font;
     4336    const float font_size = g.FontSize;
     4337    if (text == text_display_end)
     4338        return ImVec2(0.0f, font_size);
     4339    ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
     4340
     4341    // Round
     4342    text_size.x = IM_FLOOR(text_size.x + 0.95f);
     4343
     4344    return text_size;
     4345}
     4346
     4347// Find window given position, search front-to-back
     4348// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically
     4349// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
     4350// called, aka before the next Begin(). Moving window isn't affected.
     4351static void FindHoveredWindow()
     4352{
     4353    ImGuiContext& g = *GImGui;
     4354
     4355    ImGuiWindow* hovered_window = NULL;
     4356    ImGuiWindow* hovered_window_ignoring_moving_window = NULL;
     4357    if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs))
     4358        hovered_window = g.MovingWindow;
     4359
     4360    ImVec2 padding_regular = g.Style.TouchExtraPadding;
     4361    ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular;
     4362    for (int i = g.Windows.Size - 1; i >= 0; i--)
     4363    {
     4364        ImGuiWindow* window = g.Windows[i];
     4365        if (!window->Active || window->Hidden)
     4366            continue;
     4367        if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
     4368            continue;
     4369
     4370        // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
     4371        ImRect bb(window->OuterRectClipped);
     4372        if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
     4373            bb.Expand(padding_regular);
     4374        else
     4375            bb.Expand(padding_for_resize_from_edges);
     4376        if (!bb.Contains(g.IO.MousePos))
     4377            continue;
     4378
     4379        // Support for one rectangular hole in any given window
     4380        // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512)
     4381        if (window->HitTestHoleSize.x != 0)
     4382        {
     4383            ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y);
     4384            ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y);
     4385            if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos))
     4386                continue;
     4387        }
     4388
     4389        if (hovered_window == NULL)
     4390            hovered_window = window;
     4391        if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))
     4392            hovered_window_ignoring_moving_window = window;
     4393        if (hovered_window && hovered_window_ignoring_moving_window)
    42104394            break;
    4211          else
    4212             line_end++;
    4213       if (line_end >= text_end)
    4214          line_end = NULL;
    4215 
    4216       const bool is_first_line = (text == text_remaining);
    4217       bool is_last_line = false;
    4218       if (line_end == NULL)
    4219       {
    4220          is_last_line = true;
    4221          line_end = text_end;
    4222       }
    4223       if (line_end != NULL && !(is_last_line && (line_end - text_remaining) == 0))
    4224       {
    4225          const int char_count = (int)(line_end - text_remaining);
    4226          if (log_new_line || !is_first_line)
    4227             ImGui::LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, text_remaining);
    4228          else
    4229             ImGui::LogText(" %.*s", char_count, text_remaining);
    4230       }
    4231 
    4232       if (is_last_line)
    4233          break;
    4234       text_remaining = line_end + 1;
    4235    }
    4236 }
    4237 
    4238 // Internal ImGui functions to render text
    4239 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
    4240 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
    4241 {
    4242    ImGuiContext& g = *GImGui;
    4243    ImGuiWindow* window = g.CurrentWindow;
    4244 
    4245    // Hide anything after a '##' string
    4246    const char* text_display_end;
    4247    if (hide_text_after_hash)
    4248    {
    4249       text_display_end = FindRenderedTextEnd(text, text_end);
    4250    }
    4251    else
    4252    {
    4253       if (!text_end)
    4254          text_end = text + strlen(text); // FIXME-OPT
    4255       text_display_end = text_end;
    4256    }
    4257 
    4258    if (text != text_display_end)
    4259    {
    4260       window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
    4261       if (g.LogEnabled)
    4262          LogRenderedText(&pos, text, text_display_end);
    4263    }
    4264 }
    4265 
    4266 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
    4267 {
    4268    ImGuiContext& g = *GImGui;
    4269    ImGuiWindow* window = g.CurrentWindow;
    4270 
    4271    if (!text_end)
    4272       text_end = text + strlen(text); // FIXME-OPT
    4273 
    4274    if (text != text_end)
    4275    {
    4276       window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
    4277       if (g.LogEnabled)
    4278          LogRenderedText(&pos, text, text_end);
    4279    }
    4280 }
    4281 
    4282 // Default clip_rect uses (pos_min,pos_max)
    4283 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
    4284 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)
    4285 {
    4286    // Hide anything after a '##' string
    4287    const char* text_display_end = FindRenderedTextEnd(text, text_end);
    4288    const int text_len = (int)(text_display_end - text);
    4289    if (text_len == 0)
    4290       return;
    4291 
    4292    ImGuiContext& g = *GImGui;
    4293    ImGuiWindow* window = g.CurrentWindow;
    4294 
    4295    // Perform CPU side clipping for single clipped element to avoid using scissor state
    4296    ImVec2 pos = pos_min;
    4297    const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
    4298 
    4299    const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
    4300    const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
    4301    bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
    4302    if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
    4303       need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
    4304 
    4305    // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
    4306    if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
    4307    if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
    4308 
    4309    // Render
    4310    if (need_clipping)
    4311    {
    4312       ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
    4313       window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
    4314    }
    4315    else
    4316    {
    4317       window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
    4318    }
    4319    if (g.LogEnabled)
    4320       LogRenderedText(&pos, text, text_display_end);
    4321 }
    4322 
    4323 // Render a rectangle shaped with optional rounding and borders
    4324 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
    4325 {
    4326    ImGuiContext& g = *GImGui;
    4327    ImGuiWindow* window = g.CurrentWindow;
    4328    window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
    4329    const float border_size = g.Style.FrameBorderSize;
    4330    if (border && border_size > 0.0f)
    4331    {
    4332       window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
    4333       window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
    4334    }
    4335 }
    4336 
    4337 void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
    4338 {
    4339    ImGuiContext& g = *GImGui;
    4340    ImGuiWindow* window = g.CurrentWindow;
    4341    const float border_size = g.Style.FrameBorderSize;
    4342    if (border_size > 0.0f)
    4343    {
    4344       window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
    4345       window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
    4346    }
    4347 }
    4348 
    4349 // Render a triangle to denote expanded/collapsed state
    4350 void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale)
    4351 {
    4352    ImGuiContext& g = *GImGui;
    4353    ImGuiWindow* window = g.CurrentWindow;
    4354 
    4355    const float h = g.FontSize * 1.00f;
    4356    float r = h * 0.40f * scale;
    4357    ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale);
    4358 
    4359    ImVec2 a, b, c;
    4360    switch (dir)
    4361    {
    4362    case ImGuiDir_Up:
    4363    case ImGuiDir_Down:
    4364       if (dir == ImGuiDir_Up) r = -r;
    4365       center.y -= r * 0.25f;
    4366       a = ImVec2(0, 1) * r;
    4367       b = ImVec2(-0.866f, -0.5f) * r;
    4368       c = ImVec2(+0.866f, -0.5f) * r;
    4369       break;
    4370    case ImGuiDir_Left:
    4371    case ImGuiDir_Right:
    4372       if (dir == ImGuiDir_Left) r = -r;
    4373       center.x -= r * 0.25f;
    4374       a = ImVec2(1, 0) * r;
    4375       b = ImVec2(-0.500f, +0.866f) * r;
    4376       c = ImVec2(-0.500f, -0.866f) * r;
    4377       break;
    4378    case ImGuiDir_None:
    4379    case ImGuiDir_COUNT:
    4380       IM_ASSERT(0);
    4381       break;
    4382    }
    4383 
    4384    window->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text));
    4385 }
    4386 
    4387 void ImGui::RenderBullet(ImVec2 pos)
    4388 {
    4389    ImGuiContext& g = *GImGui;
    4390    ImGuiWindow* window = g.CurrentWindow;
    4391    window->DrawList->AddCircleFilled(pos, GImGui->FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8);
    4392 }
    4393 
    4394 void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz)
    4395 {
    4396    ImGuiContext& g = *GImGui;
    4397    ImGuiWindow* window = g.CurrentWindow;
    4398 
    4399    float thickness = ImMax(sz / 5.0f, 1.0f);
    4400    sz -= thickness * 0.5f;
    4401    pos += ImVec2(thickness*0.25f, thickness*0.25f);
    4402 
    4403    float third = sz / 3.0f;
    4404    float bx = pos.x + third;
    4405    float by = pos.y + sz - third * 0.5f;
    4406    window->DrawList->PathLineTo(ImVec2(bx - third, by - third));
    4407    window->DrawList->PathLineTo(ImVec2(bx, by));
    4408    window->DrawList->PathLineTo(ImVec2(bx + third * 2, by - third * 2));
    4409    window->DrawList->PathStroke(col, false, thickness);
    4410 }
    4411 
    4412 void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)
    4413 {
    4414    ImGuiContext& g = *GImGui;
    4415    if (id != g.NavId)
    4416       return;
    4417    if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
    4418       return;
    4419    ImGuiWindow* window = ImGui::GetCurrentWindow();
    4420    if (window->DC.NavHideHighlightOneFrame)
    4421       return;
    4422 
    4423    float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
    4424    ImRect display_rect = bb;
    4425    display_rect.ClipWith(window->ClipRect);
    4426    if (flags & ImGuiNavHighlightFlags_TypeDefault)
    4427    {
    4428       const float THICKNESS = 2.0f;
    4429       const float DISTANCE = 3.0f + THICKNESS * 0.5f;
    4430       display_rect.Expand(ImVec2(DISTANCE, DISTANCE));
    4431       bool fully_visible = window->ClipRect.Contains(display_rect);
    4432       if (!fully_visible)
    4433          window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
    4434       window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS*0.5f, THICKNESS*0.5f), display_rect.Max - ImVec2(THICKNESS*0.5f, THICKNESS*0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS);
    4435       if (!fully_visible)
    4436          window->DrawList->PopClipRect();
    4437    }
    4438    if (flags & ImGuiNavHighlightFlags_TypeThin)
    4439    {
    4440       window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f);
    4441    }
    4442 }
    4443 
    4444 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
    4445 // CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize)
    4446 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
    4447 {
    4448    ImGuiContext& g = *GImGui;
    4449 
    4450    const char* text_display_end;
    4451    if (hide_text_after_double_hash)
    4452       text_display_end = FindRenderedTextEnd(text, text_end);      // Hide anything after a '##' string
    4453    else
    4454       text_display_end = text_end;
    4455 
    4456    ImFont* font = g.Font;
    4457    const float font_size = g.FontSize;
    4458    if (text == text_display_end)
    4459       return ImVec2(0.0f, font_size);
    4460    ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
    4461 
    4462    // Cancel out character spacing for the last character of a line (it is baked into glyph->AdvanceX field)
    4463    const float font_scale = font_size / font->FontSize;
    4464    const float character_spacing_x = 1.0f * font_scale;
    4465    if (text_size.x > 0.0f)
    4466       text_size.x -= character_spacing_x;
    4467    text_size.x = (float)(int)(text_size.x + 0.95f);
    4468 
    4469    return text_size;
    4470 }
    4471 
    4472 // Helper to calculate coarse clipping of large list of evenly sized items.
    4473 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
    4474 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
    4475 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
    4476 {
    4477    ImGuiContext& g = *GImGui;
    4478    ImGuiWindow* window = g.CurrentWindow;
    4479    if (g.LogEnabled)
    4480    {
    4481       // If logging is active, do not perform any clipping
    4482       *out_items_display_start = 0;
    4483       *out_items_display_end = items_count;
    4484       return;
    4485    }
    4486    if (window->SkipItems)
    4487    {
    4488       *out_items_display_start = *out_items_display_end = 0;
    4489       return;
    4490    }
    4491 
    4492    const ImVec2 pos = window->DC.CursorPos;
    4493    int start = (int)((window->ClipRect.Min.y - pos.y) / items_height);
    4494    int end = (int)((window->ClipRect.Max.y - pos.y) / items_height);
    4495    if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Up) // When performing a navigation request, ensure we have one item extra in the direction we are moving to
    4496       start--;
    4497    if (g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down)
    4498       end++;
    4499 
    4500    start = ImClamp(start, 0, items_count);
    4501    end = ImClamp(end + 1, start, items_count);
    4502    *out_items_display_start = start;
    4503    *out_items_display_end = end;
    4504 }
    4505 
    4506 // Find window given position, search front-to-back
    4507 // FIXME: Note that we have a lag here because WindowRectClipped is updated in Begin() so windows moved by user via SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is called, aka before the next Begin(). Moving window thankfully isn't affected.
    4508 static ImGuiWindow* FindHoveredWindow()
    4509 {
    4510    ImGuiContext& g = *GImGui;
    4511    for (int i = g.Windows.Size - 1; i >= 0; i--)
    4512    {
    4513       ImGuiWindow* window = g.Windows[i];
    4514       if (!window->Active)
    4515          continue;
    4516       if (window->Flags & ImGuiWindowFlags_NoInputs)
    4517          continue;
    4518 
    4519       // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
    4520       ImRect bb(window->WindowRectClipped.Min - g.Style.TouchExtraPadding, window->WindowRectClipped.Max + g.Style.TouchExtraPadding);
    4521       if (bb.Contains(g.IO.MousePos))
    4522          return window;
    4523    }
    4524    return NULL;
     4395    }
     4396
     4397    g.HoveredWindow = hovered_window;
     4398    g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
     4399    g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;
    45254400}
    45264401
     
    45304405bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
    45314406{
    4532    ImGuiContext& g = *GImGui;
    4533 
    4534    // Clip
    4535    ImRect rect_clipped(r_min, r_max);
    4536    if (clip)
    4537       rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
    4538 
    4539    // Expand for touch input
    4540    const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
    4541    return rect_for_touch.Contains(g.IO.MousePos);
    4542 }
    4543 
    4544 static bool IsKeyPressedMap(ImGuiKey key, bool repeat)
    4545 {
    4546    const int key_index = GImGui->IO.KeyMap[key];
    4547    return (key_index >= 0) ? ImGui::IsKeyPressed(key_index, repeat) : false;
     4407    ImGuiContext& g = *GImGui;
     4408
     4409    // Clip
     4410    ImRect rect_clipped(r_min, r_max);
     4411    if (clip)
     4412        rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
     4413
     4414    // Expand for touch input
     4415    const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
     4416    if (!rect_for_touch.Contains(g.IO.MousePos))
     4417        return false;
     4418    return true;
    45484419}
    45494420
    45504421int ImGui::GetKeyIndex(ImGuiKey imgui_key)
    45514422{
    4552    IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
    4553    return GImGui->IO.KeyMap[imgui_key];
    4554 }
    4555 
    4556 // Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]!
     4423    IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
     4424    ImGuiContext& g = *GImGui;
     4425    return g.IO.KeyMap[imgui_key];
     4426}
     4427
     4428// Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]!
     4429// Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]!
    45574430bool ImGui::IsKeyDown(int user_key_index)
    45584431{
    4559    if (user_key_index < 0) return false;
    4560    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown));
    4561    return GImGui->IO.KeysDown[user_key_index];
    4562 }
    4563 
    4564 int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
    4565 {
    4566    if (t == 0.0f)
    4567       return 1;
    4568    if (t <= repeat_delay || repeat_rate <= 0.0f)
    4569       return 0;
    4570    const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate);
    4571    return (count > 0) ? count : 0;
     4432    if (user_key_index < 0)
     4433        return false;
     4434    ImGuiContext& g = *GImGui;
     4435    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
     4436    return g.IO.KeysDown[user_key_index];
     4437}
     4438
     4439// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
     4440// t1 = current time (e.g.: g.Time)
     4441// An event is triggered at:
     4442//  t = 0.0f     t = repeat_delay,    t = repeat_delay + repeat_rate*N
     4443int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
     4444{
     4445    if (t1 == 0.0f)
     4446        return 1;
     4447    if (t0 >= t1)
     4448        return 0;
     4449    if (repeat_rate <= 0.0f)
     4450        return (t0 < repeat_delay) && (t1 >= repeat_delay);
     4451    const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
     4452    const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
     4453    const int count = count_t1 - count_t0;
     4454    return count;
    45724455}
    45734456
    45744457int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
    45754458{
    4576    ImGuiContext& g = *GImGui;
    4577    if (key_index < 0) return false;
    4578    IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
    4579    const float t = g.IO.KeysDownDuration[key_index];
    4580    return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate);
     4459    ImGuiContext& g = *GImGui;
     4460    if (key_index < 0)
     4461        return 0;
     4462    IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
     4463    const float t = g.IO.KeysDownDuration[key_index];
     4464    return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
    45814465}
    45824466
    45834467bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
    45844468{
    4585    ImGuiContext& g = *GImGui;
    4586    if (user_key_index < 0) return false;
    4587    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
    4588    const float t = g.IO.KeysDownDuration[user_key_index];
    4589    if (t == 0.0f)
    4590       return true;
    4591    if (repeat && t > g.IO.KeyRepeatDelay)
    4592       return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
    4593    return false;
     4469    ImGuiContext& g = *GImGui;
     4470    if (user_key_index < 0)
     4471        return false;
     4472    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
     4473    const float t = g.IO.KeysDownDuration[user_key_index];
     4474    if (t == 0.0f)
     4475        return true;
     4476    if (repeat && t > g.IO.KeyRepeatDelay)
     4477        return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
     4478    return false;
    45944479}
    45954480
    45964481bool ImGui::IsKeyReleased(int user_key_index)
    45974482{
    4598    ImGuiContext& g = *GImGui;
    4599    if (user_key_index < 0) return false;
    4600    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
    4601    return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
    4602 }
    4603 
    4604 bool ImGui::IsMouseDown(int button)
    4605 {
    4606    ImGuiContext& g = *GImGui;
    4607    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
    4608    return g.IO.MouseDown[button];
    4609 }
    4610 
    4611 bool ImGui::IsAnyMouseDown()
    4612 {
    4613    ImGuiContext& g = *GImGui;
    4614    for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
    4615       if (g.IO.MouseDown[n])
    4616          return true;
    4617    return false;
    4618 }
    4619 
    4620 bool ImGui::IsMouseClicked(int button, bool repeat)
    4621 {
    4622    ImGuiContext& g = *GImGui;
    4623    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
    4624    const float t = g.IO.MouseDownDuration[button];
    4625    if (t == 0.0f)
    4626       return true;
    4627 
    4628    if (repeat && t > g.IO.KeyRepeatDelay)
    4629    {
    4630       float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate;
    4631       if ((fmodf(t - delay, rate) > rate*0.5f) != (fmodf(t - delay - g.IO.DeltaTime, rate) > rate*0.5f))
    4632          return true;
    4633    }
    4634 
    4635    return false;
    4636 }
    4637 
    4638 bool ImGui::IsMouseReleased(int button)
    4639 {
    4640    ImGuiContext& g = *GImGui;
    4641    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
    4642    return g.IO.MouseReleased[button];
    4643 }
    4644 
    4645 bool ImGui::IsMouseDoubleClicked(int button)
    4646 {
    4647    ImGuiContext& g = *GImGui;
    4648    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
    4649    return g.IO.MouseDoubleClicked[button];
    4650 }
    4651 
    4652 bool ImGui::IsMouseDragging(int button, float lock_threshold)
    4653 {
    4654    ImGuiContext& g = *GImGui;
    4655    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
    4656    if (!g.IO.MouseDown[button])
    4657       return false;
    4658    if (lock_threshold < 0.0f)
    4659       lock_threshold = g.IO.MouseDragThreshold;
    4660    return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
     4483    ImGuiContext& g = *GImGui;
     4484    if (user_key_index < 0) return false;
     4485    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
     4486    return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
     4487}
     4488
     4489bool ImGui::IsMouseDown(ImGuiMouseButton button)
     4490{
     4491    ImGuiContext& g = *GImGui;
     4492    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
     4493    return g.IO.MouseDown[button];
     4494}
     4495
     4496bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
     4497{
     4498    ImGuiContext& g = *GImGui;
     4499    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
     4500    const float t = g.IO.MouseDownDuration[button];
     4501    if (t == 0.0f)
     4502        return true;
     4503
     4504    if (repeat && t > g.IO.KeyRepeatDelay)
     4505    {
     4506        // 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.
     4507        int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f);
     4508        if (amount > 0)
     4509            return true;
     4510    }
     4511    return false;
     4512}
     4513
     4514bool ImGui::IsMouseReleased(ImGuiMouseButton button)
     4515{
     4516    ImGuiContext& g = *GImGui;
     4517    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
     4518    return g.IO.MouseReleased[button];
     4519}
     4520
     4521bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
     4522{
     4523    ImGuiContext& g = *GImGui;
     4524    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
     4525    return g.IO.MouseDoubleClicked[button];
     4526}
     4527
     4528// Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
     4529// [Internal] This doesn't test if the button is pressed
     4530bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold)
     4531{
     4532    ImGuiContext& g = *GImGui;
     4533    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
     4534    if (lock_threshold < 0.0f)
     4535        lock_threshold = g.IO.MouseDragThreshold;
     4536    return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
     4537}
     4538
     4539bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
     4540{
     4541    ImGuiContext& g = *GImGui;
     4542    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
     4543    if (!g.IO.MouseDown[button])
     4544        return false;
     4545    return IsMouseDragPastThreshold(button, lock_threshold);
    46614546}
    46624547
    46634548ImVec2 ImGui::GetMousePos()
    46644549{
    4665    return GImGui->IO.MousePos;
     4550    ImGuiContext& g = *GImGui;
     4551    return g.IO.MousePos;
    46664552}
    46674553
     
    46694555ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
    46704556{
    4671    ImGuiContext& g = *GImGui;
    4672    if (g.CurrentPopupStack.Size > 0)
    4673       return g.OpenPopupStack[g.CurrentPopupStack.Size - 1].OpenMousePos;
    4674    return g.IO.MousePos;
    4675 }
    4676 
    4677 // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position
     4557    ImGuiContext& g = *GImGui;
     4558    if (g.BeginPopupStack.Size > 0)
     4559        return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;
     4560    return g.IO.MousePos;
     4561}
     4562
     4563// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
    46784564bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
    46794565{
    4680    if (mouse_pos == NULL)
    4681       mouse_pos = &GImGui->IO.MousePos;
    4682    const float MOUSE_INVALID = -256000.0f;
    4683    return mouse_pos->x >= MOUSE_INVALID && mouse_pos->y >= MOUSE_INVALID;
    4684 }
    4685 
     4566    // The assert is only to silence a false-positive in XCode Static Analysis.
     4567    // 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).
     4568    IM_ASSERT(GImGui != NULL);
     4569    const float MOUSE_INVALID = -256000.0f;
     4570    ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
     4571    return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
     4572}
     4573
     4574bool ImGui::IsAnyMouseDown()
     4575{
     4576    ImGuiContext& g = *GImGui;
     4577    for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
     4578        if (g.IO.MouseDown[n])
     4579            return true;
     4580    return false;
     4581}
     4582
     4583// Return the delta from the initial clicking position while the mouse button is clicked or was just released.
     4584// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
    46864585// NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window.
    4687 ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
    4688 {
    4689    ImGuiContext& g = *GImGui;
    4690    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
    4691    if (lock_threshold < 0.0f)
    4692       lock_threshold = g.IO.MouseDragThreshold;
    4693    if (g.IO.MouseDown[button])
    4694       if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
    4695          return g.IO.MousePos - g.IO.MouseClickedPos[button];     // Assume we can only get active with left-mouse button (at the moment).
    4696    return ImVec2(0.0f, 0.0f);
    4697 }
    4698 
    4699 void ImGui::ResetMouseDragDelta(int button)
    4700 {
    4701    ImGuiContext& g = *GImGui;
    4702    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
    4703    // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
    4704    g.IO.MouseClickedPos[button] = g.IO.MousePos;
     4586ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold)
     4587{
     4588    ImGuiContext& g = *GImGui;
     4589    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
     4590    if (lock_threshold < 0.0f)
     4591        lock_threshold = g.IO.MouseDragThreshold;
     4592    if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
     4593        if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
     4594            if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button]))
     4595                return g.IO.MousePos - g.IO.MouseClickedPos[button];
     4596    return ImVec2(0.0f, 0.0f);
     4597}
     4598
     4599void ImGui::ResetMouseDragDelta(ImGuiMouseButton button)
     4600{
     4601    ImGuiContext& g = *GImGui;
     4602    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
     4603    // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
     4604    g.IO.MouseClickedPos[button] = g.IO.MousePos;
    47054605}
    47064606
    47074607ImGuiMouseCursor ImGui::GetMouseCursor()
    47084608{
    4709    return GImGui->MouseCursor;
     4609    return GImGui->MouseCursor;
    47104610}
    47114611
    47124612void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
    47134613{
    4714    GImGui->MouseCursor = cursor_type;
     4614    GImGui->MouseCursor = cursor_type;
    47154615}
    47164616
    47174617void ImGui::CaptureKeyboardFromApp(bool capture)
    47184618{
    4719    GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
     4619    GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
    47204620}
    47214621
    47224622void ImGui::CaptureMouseFromApp(bool capture)
    47234623{
    4724    GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
     4624    GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
    47254625}
    47264626
    47274627bool ImGui::IsItemActive()
    47284628{
    4729    ImGuiContext& g = *GImGui;
    4730    if (g.ActiveId)
    4731    {
    4732       ImGuiWindow* window = g.CurrentWindow;
    4733       return g.ActiveId == window->DC.LastItemId;
    4734    }
    4735    return false;
     4629    ImGuiContext& g = *GImGui;
     4630    if (g.ActiveId)
     4631    {
     4632        ImGuiWindow* window = g.CurrentWindow;
     4633        return g.ActiveId == window->DC.LastItemId;
     4634    }
     4635    return false;
     4636}
     4637
     4638bool ImGui::IsItemActivated()
     4639{
     4640    ImGuiContext& g = *GImGui;
     4641    if (g.ActiveId)
     4642    {
     4643        ImGuiWindow* window = g.CurrentWindow;
     4644        if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
     4645            return true;
     4646    }
     4647    return false;
     4648}
     4649
     4650bool ImGui::IsItemDeactivated()
     4651{
     4652    ImGuiContext& g = *GImGui;
     4653    ImGuiWindow* window = g.CurrentWindow;
     4654    if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
     4655        return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
     4656    return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
     4657}
     4658
     4659bool ImGui::IsItemDeactivatedAfterEdit()
     4660{
     4661    ImGuiContext& g = *GImGui;
     4662    return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));
    47364663}
    47374664
    47384665bool ImGui::IsItemFocused()
    47394666{
    4740    ImGuiContext& g = *GImGui;
    4741    return g.NavId && !g.NavDisableHighlight && g.NavId == g.CurrentWindow->DC.LastItemId;
    4742 }
    4743 
    4744 bool ImGui::IsItemClicked(int mouse_button)
    4745 {
    4746    return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_Default);
     4667    ImGuiContext& g = *GImGui;
     4668    ImGuiWindow* window = g.CurrentWindow;
     4669
     4670    if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId)
     4671        return false;
     4672    return true;
     4673}
     4674
     4675bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)
     4676{
     4677    return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
     4678}
     4679
     4680bool ImGui::IsItemToggledOpen()
     4681{
     4682    ImGuiContext& g = *GImGui;
     4683    return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
     4684}
     4685
     4686bool ImGui::IsItemToggledSelection()
     4687{
     4688    ImGuiContext& g = *GImGui;
     4689    return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
    47474690}
    47484691
    47494692bool ImGui::IsAnyItemHovered()
    47504693{
    4751    ImGuiContext& g = *GImGui;
    4752    return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
     4694    ImGuiContext& g = *GImGui;
     4695    return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
    47534696}
    47544697
    47554698bool ImGui::IsAnyItemActive()
    47564699{
    4757    ImGuiContext& g = *GImGui;
    4758    return g.ActiveId != 0;
     4700    ImGuiContext& g = *GImGui;
     4701    return g.ActiveId != 0;
    47594702}
    47604703
    47614704bool ImGui::IsAnyItemFocused()
    47624705{
    4763    ImGuiContext& g = *GImGui;
    4764    return g.NavId != 0 && !g.NavDisableHighlight;
     4706    ImGuiContext& g = *GImGui;
     4707    return g.NavId != 0 && !g.NavDisableHighlight;
    47654708}
    47664709
    47674710bool ImGui::IsItemVisible()
    47684711{
    4769    ImGuiWindow* window = GetCurrentWindowRead();
    4770    return window->ClipRect.Overlaps(window->DC.LastItemRect);
     4712    ImGuiWindow* window = GetCurrentWindowRead();
     4713    return window->ClipRect.Overlaps(window->DC.LastItemRect);
     4714}
     4715
     4716bool ImGui::IsItemEdited()
     4717{
     4718    ImGuiWindow* window = GetCurrentWindowRead();
     4719    return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0;
    47714720}
    47724721
     
    47744723void ImGui::SetItemAllowOverlap()
    47754724{
    4776    ImGuiContext& g = *GImGui;
    4777    if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
    4778       g.HoveredIdAllowOverlap = true;
    4779    if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
    4780       g.ActiveIdAllowOverlap = true;
     4725    ImGuiContext& g = *GImGui;
     4726    if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
     4727        g.HoveredIdAllowOverlap = true;
     4728    if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
     4729        g.ActiveIdAllowOverlap = true;
    47814730}
    47824731
    47834732ImVec2 ImGui::GetItemRectMin()
    47844733{
    4785    ImGuiWindow* window = GetCurrentWindowRead();
    4786    return window->DC.LastItemRect.Min;
     4734    ImGuiWindow* window = GetCurrentWindowRead();
     4735    return window->DC.LastItemRect.Min;
    47874736}
    47884737
    47894738ImVec2 ImGui::GetItemRectMax()
    47904739{
    4791    ImGuiWindow* window = GetCurrentWindowRead();
    4792    return window->DC.LastItemRect.Max;
     4740    ImGuiWindow* window = GetCurrentWindowRead();
     4741    return window->DC.LastItemRect.Max;
    47934742}
    47944743
    47954744ImVec2 ImGui::GetItemRectSize()
    47964745{
    4797    ImGuiWindow* window = GetCurrentWindowRead();
    4798    return window->DC.LastItemRect.GetSize();
     4746    ImGuiWindow* window = GetCurrentWindowRead();
     4747    return window->DC.LastItemRect.GetSize();
    47994748}
    48004749
    48014750static ImRect GetViewportRect()
    48024751{
    4803    ImGuiContext& g = *GImGui;
    4804    if (g.IO.DisplayVisibleMin.x != g.IO.DisplayVisibleMax.x && g.IO.DisplayVisibleMin.y != g.IO.DisplayVisibleMax.y)
    4805       return ImRect(g.IO.DisplayVisibleMin, g.IO.DisplayVisibleMax);
    4806    return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
    4807 }
    4808 
    4809 // Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first.
    4810 void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip)
    4811 {
    4812    ImGuiContext& g = *GImGui;
    4813    char window_name[16];
    4814    ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
    4815    if (override_previous_tooltip)
    4816       if (ImGuiWindow* window = FindWindowByName(window_name))
    4817          if (window->Active)
    4818          {
    4819             // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
    4820             window->HiddenFrames = 1;
    4821             ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
    4822          }
    4823    ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoNav;
    4824    Begin(window_name, NULL, flags | extra_flags);
    4825 }
    4826 
    4827 void ImGui::SetTooltipV(const char* fmt, va_list args)
    4828 {
    4829    BeginTooltipEx(0, true);
    4830    TextV(fmt, args);
    4831    EndTooltip();
    4832 }
    4833 
    4834 void ImGui::SetTooltip(const char* fmt, ...)
    4835 {
    4836    va_list args;
    4837    va_start(args, fmt);
    4838    SetTooltipV(fmt, args);
    4839    va_end(args);
    4840 }
    4841 
    4842 void ImGui::BeginTooltip()
    4843 {
    4844    BeginTooltipEx(0, false);
    4845 }
    4846 
    4847 void ImGui::EndTooltip()
    4848 {
    4849    IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip);   // Mismatched BeginTooltip()/EndTooltip() calls
    4850    End();
    4851 }
    4852 
    4853 // Mark popup as open (toggle toward open state).
    4854 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
    4855 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
    4856 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
    4857 void ImGui::OpenPopupEx(ImGuiID id)
    4858 {
    4859    ImGuiContext& g = *GImGui;
    4860    ImGuiWindow* parent_window = g.CurrentWindow;
    4861    int current_stack_size = g.CurrentPopupStack.Size;
    4862    ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
    4863    popup_ref.PopupId = id;
    4864    popup_ref.Window = NULL;
    4865    popup_ref.ParentWindow = parent_window;
    4866    popup_ref.OpenFrameCount = g.FrameCount;
    4867    popup_ref.OpenParentId = parent_window->IDStack.back();
    4868    popup_ref.OpenMousePos = g.IO.MousePos;
    4869    popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
    4870 
    4871    //printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id);
    4872    if (g.OpenPopupStack.Size < current_stack_size + 1)
    4873    {
    4874       g.OpenPopupStack.push_back(popup_ref);
    4875    }
    4876    else
    4877    {
    4878       // Close child popups if any
    4879       g.OpenPopupStack.resize(current_stack_size + 1);
    4880 
    4881       // 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
    4882       // 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
    4883       // 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.
    4884       if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
    4885          g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
    4886       else
    4887          g.OpenPopupStack[current_stack_size] = popup_ref;
    4888 
    4889       // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
    4890       // This is equivalent to what ClosePopupToLevel() does.
    4891       //if (g.OpenPopupStack[current_stack_size].PopupId == id)
    4892       //    FocusWindow(parent_window);
    4893    }
    4894 }
    4895 
    4896 void ImGui::OpenPopup(const char* str_id)
    4897 {
    4898    ImGuiContext& g = *GImGui;
    4899    OpenPopupEx(g.CurrentWindow->GetID(str_id));
    4900 }
    4901 
    4902 void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
    4903 {
    4904    ImGuiContext& g = *GImGui;
    4905    if (g.OpenPopupStack.empty())
    4906       return;
    4907 
    4908    // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
    4909    // Don't close our own child popup windows.
    4910    int n = 0;
    4911    if (ref_window)
    4912    {
    4913       for (n = 0; n < g.OpenPopupStack.Size; n++)
    4914       {
    4915          ImGuiPopupRef& popup = g.OpenPopupStack[n];
    4916          if (!popup.Window)
    4917             continue;
    4918          IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
    4919          if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
    4920             continue;
    4921 
    4922          // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow)
    4923          bool has_focus = false;
    4924          for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++)
    4925             has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow);
    4926          if (!has_focus)
    4927             break;
    4928       }
    4929    }
    4930    if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the block below
    4931       ClosePopupToLevel(n);
    4932 }
    4933 
    4934 ImGuiWindow* ImGui::GetFrontMostPopupModal()
    4935 {
    4936    ImGuiContext& g = *GImGui;
    4937    for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
    4938       if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
    4939          if (popup->Flags & ImGuiWindowFlags_Modal)
    4940             return popup;
    4941    return NULL;
    4942 }
    4943 
    4944 static void ClosePopupToLevel(int remaining)
    4945 {
    4946    IM_ASSERT(remaining >= 0);
    4947    ImGuiContext& g = *GImGui;
    4948    ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining - 1].Window : g.OpenPopupStack[0].ParentWindow;
    4949    if (g.NavLayer == 0)
    4950       focus_window = NavRestoreLastChildNavWindow(focus_window);
    4951    ImGui::FocusWindow(focus_window);
    4952    focus_window->DC.NavHideHighlightOneFrame = true;
    4953    g.OpenPopupStack.resize(remaining);
    4954 }
    4955 
    4956 void ImGui::ClosePopup(ImGuiID id)
    4957 {
    4958    if (!IsPopupOpen(id))
    4959       return;
    4960    ImGuiContext& g = *GImGui;
    4961    ClosePopupToLevel(g.OpenPopupStack.Size - 1);
    4962 }
    4963 
    4964 // Close the popup we have begin-ed into.
    4965 void ImGui::CloseCurrentPopup()
    4966 {
    4967    ImGuiContext& g = *GImGui;
    4968    int popup_idx = g.CurrentPopupStack.Size - 1;
    4969    if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
    4970       return;
    4971    while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
    4972       popup_idx--;
    4973    ClosePopupToLevel(popup_idx);
    4974 }
    4975 
    4976 bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
    4977 {
    4978    ImGuiContext& g = *GImGui;
    4979    if (!IsPopupOpen(id))
    4980    {
    4981       g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
    4982       return false;
    4983    }
    4984 
    4985    char name[20];
    4986    if (extra_flags & ImGuiWindowFlags_ChildMenu)
    4987       ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.CurrentPopupStack.Size);    // Recycle windows based on depth
    4988    else
    4989       ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
    4990 
    4991    bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup);
    4992    if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
    4993       EndPopup();
    4994 
    4995    return is_open;
    4996 }
    4997 
    4998 bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
    4999 {
    5000    ImGuiContext& g = *GImGui;
    5001    if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
    5002    {
    5003       g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
    5004       return false;
    5005    }
    5006    return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
    5007 }
    5008 
    5009 bool ImGui::IsPopupOpen(ImGuiID id)
    5010 {
    5011    ImGuiContext& g = *GImGui;
    5012    return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id;
    5013 }
    5014 
    5015 bool ImGui::IsPopupOpen(const char* str_id)
    5016 {
    5017    ImGuiContext& g = *GImGui;
    5018    return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
    5019 }
    5020 
    5021 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
    5022 {
    5023    ImGuiContext& g = *GImGui;
    5024    ImGuiWindow* window = g.CurrentWindow;
    5025    const ImGuiID id = window->GetID(name);
    5026    if (!IsPopupOpen(id))
    5027    {
    5028       g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
    5029       return false;
    5030    }
    5031 
    5032    // Center modal windows by default
    5033    // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
    5034    if (g.NextWindowData.PosCond == 0)
    5035       SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
    5036 
    5037    bool is_open = Begin(name, p_open, flags | ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings);
    5038    if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
    5039    {
    5040       EndPopup();
    5041       if (is_open)
    5042          ClosePopup(id);
    5043       return false;
    5044    }
    5045 
    5046    return is_open;
    5047 }
    5048 
    5049 static void NavProcessMoveRequestWrapAround(ImGuiWindow* window)
    5050 {
    5051    ImGuiContext& g = *GImGui;
    5052    if (g.NavWindow == window && NavMoveRequestButNoResultYet())
    5053       if ((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == 0)
    5054       {
    5055          g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
    5056          ImGui::NavMoveRequestCancel();
    5057          g.NavWindow->NavRectRel[0].Min.y = g.NavWindow->NavRectRel[0].Max.y = ((g.NavMoveDir == ImGuiDir_Up) ? ImMax(window->SizeFull.y, window->SizeContents.y) : 0.0f) - window->Scroll.y;
    5058       }
    5059 }
    5060 
    5061 void ImGui::EndPopup()
    5062 {
    5063    ImGuiContext& g = *GImGui; (void)g;
    5064    IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup);  // Mismatched BeginPopup()/EndPopup() calls
    5065    IM_ASSERT(g.CurrentPopupStack.Size > 0);
    5066 
    5067    // Make all menus and popups wrap around for now, may need to expose that policy.
    5068    NavProcessMoveRequestWrapAround(g.CurrentWindow);
    5069 
    5070    End();
    5071 }
    5072 
    5073 bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button)
    5074 {
    5075    ImGuiWindow* window = GImGui->CurrentWindow;
    5076    if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
    5077    {
    5078       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!
    5079       IM_ASSERT(id != 0);                                                  // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
    5080       OpenPopupEx(id);
    5081       return true;
    5082    }
    5083    return false;
    5084 }
    5085 
    5086 // This is a helper to handle the simplest case of associating one named popup to one given widget.
    5087 // You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
    5088 // You can pass a NULL str_id to use the identifier of the last item.
    5089 bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
    5090 {
    5091    ImGuiWindow* window = GImGui->CurrentWindow;
    5092    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!
    5093    IM_ASSERT(id != 0);                                                  // However, you cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
    5094    if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
    5095       OpenPopupEx(id);
    5096    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
    5097 }
    5098 
    5099 bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items)
    5100 {
    5101    if (!str_id)
    5102       str_id = "window_context";
    5103    ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
    5104    if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
    5105       if (also_over_items || !IsAnyItemHovered())
    5106          OpenPopupEx(id);
    5107    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
    5108 }
    5109 
    5110 bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
    5111 {
    5112    if (!str_id)
    5113       str_id = "void_context";
    5114    ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
    5115    if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
    5116       OpenPopupEx(id);
    5117    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
    5118 }
    5119 
    5120 static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
    5121 {
    5122    ImGuiContext& g = *GImGui;
    5123    ImGuiWindow* parent_window = ImGui::GetCurrentWindow();
    5124    ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow;
    5125    flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove);  // Inherit the NoMove flag
    5126 
    5127    const ImVec2 content_avail = ImGui::GetContentRegionAvail();
    5128    ImVec2 size = ImFloor(size_arg);
    5129    const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
    5130    if (size.x <= 0.0f)
    5131       size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
    5132    if (size.y <= 0.0f)
    5133       size.y = ImMax(content_avail.y + size.y, 4.0f);
    5134 
    5135    const float backup_border_size = g.Style.ChildBorderSize;
    5136    if (!border)
    5137       g.Style.ChildBorderSize = 0.0f;
    5138    flags |= extra_flags;
    5139 
    5140    char title[256];
    5141    if (name)
    5142       ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s", parent_window->Name, name);
    5143    else
    5144       ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id);
    5145 
    5146    ImGui::SetNextWindowSize(size);
    5147    bool ret = ImGui::Begin(title, NULL, flags);
    5148    ImGuiWindow* child_window = ImGui::GetCurrentWindow();
    5149    child_window->ChildId = id;
    5150    child_window->AutoFitChildAxises = auto_fit_axises;
    5151    g.Style.ChildBorderSize = backup_border_size;
    5152 
    5153    // Process navigation-in immediately so NavInit can run on first frame
    5154    if (!(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll) && g.NavActivateId == id)
    5155    {
    5156       ImGui::FocusWindow(child_window);
    5157       ImGui::NavInitWindow(child_window, false);
    5158       ImGui::SetActiveID(id + 1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item
    5159       g.ActiveIdSource = ImGuiInputSource_Nav;
    5160    }
    5161 
    5162    return ret;
     4752    ImGuiContext& g = *GImGui;
     4753    return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
     4754}
     4755
     4756bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
     4757{
     4758    ImGuiContext& g = *GImGui;
     4759    ImGuiWindow* parent_window = g.CurrentWindow;
     4760
     4761    flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow;
     4762    flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove);  // Inherit the NoMove flag
     4763
     4764    // Size
     4765    const ImVec2 content_avail = GetContentRegionAvail();
     4766    ImVec2 size = ImFloor(size_arg);
     4767    const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
     4768    if (size.x <= 0.0f)
     4769        size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
     4770    if (size.y <= 0.0f)
     4771        size.y = ImMax(content_avail.y + size.y, 4.0f);
     4772    SetNextWindowSize(size);
     4773
     4774    // 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.
     4775    char title[256];
     4776    if (name)
     4777        ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id);
     4778    else
     4779        ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id);
     4780
     4781    const float backup_border_size = g.Style.ChildBorderSize;
     4782    if (!border)
     4783        g.Style.ChildBorderSize = 0.0f;
     4784    bool ret = Begin(title, NULL, flags);
     4785    g.Style.ChildBorderSize = backup_border_size;
     4786
     4787    ImGuiWindow* child_window = g.CurrentWindow;
     4788    child_window->ChildId = id;
     4789    child_window->AutoFitChildAxises = (ImS8)auto_fit_axises;
     4790
     4791    // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
     4792    // While this is not really documented/defined, it seems that the expected thing to do.
     4793    if (child_window->BeginCount == 1)
     4794        parent_window->DC.CursorPos = child_window->Pos;
     4795
     4796    // Process navigation-in immediately so NavInit can run on first frame
     4797    if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
     4798    {
     4799        FocusWindow(child_window);
     4800        NavInitWindow(child_window, false);
     4801        SetActiveID(id + 1, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item
     4802        g.ActiveIdSource = ImGuiInputSource_Nav;
     4803    }
     4804    return ret;
    51634805}
    51644806
    51654807bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
    51664808{
    5167    ImGuiWindow* window = GetCurrentWindow();
    5168    return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
     4809    ImGuiWindow* window = GetCurrentWindow();
     4810    return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
    51694811}
    51704812
    51714813bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
    51724814{
    5173    IM_ASSERT(id != 0);
    5174    return BeginChildEx(NULL, id, size_arg, border, extra_flags);
     4815    IM_ASSERT(id != 0);
     4816    return BeginChildEx(NULL, id, size_arg, border, extra_flags);
    51754817}
    51764818
    51774819void ImGui::EndChild()
    51784820{
    5179    ImGuiContext& g = *GImGui;
    5180    ImGuiWindow* window = g.CurrentWindow;
    5181 
    5182    IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);   // Mismatched BeginChild()/EndChild() callss
    5183    if (window->BeginCount > 1)
    5184    {
    5185       End();
    5186    }
    5187    else
    5188    {
    5189       // When using auto-filling child window, we don't provide full width/height to ItemSize so that it doesn't feed back into automatic size-fitting.
    5190       ImVec2 sz = GetWindowSize();
    5191       if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
    5192          sz.x = ImMax(4.0f, sz.x);
    5193       if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
    5194          sz.y = ImMax(4.0f, sz.y);
    5195       End();
    5196 
    5197       ImGuiWindow* parent_window = g.CurrentWindow;
    5198       ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
    5199       ItemSize(sz);
    5200       if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
    5201       {
    5202          ItemAdd(bb, window->ChildId);
    5203          RenderNavHighlight(bb, window->ChildId);
    5204 
    5205          // When browsing a window that has no activable items (scroll only) we keep a highlight on the child
    5206          if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
    5207             RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
    5208       }
    5209       else
    5210       {
    5211          // Not navigable into
    5212          ItemAdd(bb, 0);
    5213       }
    5214    }
     4821    ImGuiContext& g = *GImGui;
     4822    ImGuiWindow* window = g.CurrentWindow;
     4823
     4824    IM_ASSERT(g.WithinEndChild == false);
     4825    IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);   // Mismatched BeginChild()/EndChild() calls
     4826
     4827    g.WithinEndChild = true;
     4828    if (window->BeginCount > 1)
     4829    {
     4830        End();
     4831    }
     4832    else
     4833    {
     4834        ImVec2 sz = window->Size;
     4835        if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
     4836            sz.x = ImMax(4.0f, sz.x);
     4837        if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
     4838            sz.y = ImMax(4.0f, sz.y);
     4839        End();
     4840
     4841        ImGuiWindow* parent_window = g.CurrentWindow;
     4842        ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
     4843        ItemSize(sz);
     4844        if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
     4845        {
     4846            ItemAdd(bb, window->ChildId);
     4847            RenderNavHighlight(bb, window->ChildId);
     4848
     4849            // When browsing a window that has no activable items (scroll only) we keep a highlight on the child
     4850            if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
     4851                RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
     4852        }
     4853        else
     4854        {
     4855            // Not navigable into
     4856            ItemAdd(bb, 0);
     4857        }
     4858    }
     4859    g.WithinEndChild = false;
    52154860}
    52164861
     
    52184863bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)
    52194864{
    5220    ImGuiContext& g = *GImGui;
    5221    const ImGuiStyle& style = g.Style;
    5222    PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
    5223    PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
    5224    PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
    5225    PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
    5226    return BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);
     4865    ImGuiContext& g = *GImGui;
     4866    const ImGuiStyle& style = g.Style;
     4867    PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
     4868    PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
     4869    PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
     4870    PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
     4871    bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);
     4872    PopStyleVar(3);
     4873    PopStyleColor();
     4874    return ret;
    52274875}
    52284876
    52294877void ImGui::EndChildFrame()
    52304878{
    5231    EndChild();
    5232    PopStyleVar(3);
    5233    PopStyleColor();
    5234 }
    5235 
    5236 // Save and compare stack sizes on Begin()/End() to detect usage errors
    5237 static void CheckStacksSize(ImGuiWindow* window, bool write)
    5238 {
    5239    // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
    5240    ImGuiContext& g = *GImGui;
    5241    int* p_backup = &window->DC.StackSizesBackup[0];
    5242    { int current = window->IDStack.Size;       if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!");   p_backup++; }    // Too few or too many PopID()/TreePop()
    5243    { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!");                p_backup++; }    // Too few or too many EndGroup()
    5244    { int current = g.CurrentPopupStack.Size;   if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++; }// Too few or too many EndMenu()/EndPopup()
    5245                                                                                                                                                                                          // 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.
    5246    { int current = g.ColorModifiers.Size;      if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!");       p_backup++; }    // Too few or too many PopStyleColor()
    5247    { int current = g.StyleModifiers.Size;      if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!");           p_backup++; }    // Too few or too many PopStyleVar()
    5248    { int current = g.FontStack.Size;           if (write) *p_backup = current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!");                   p_backup++; }    // Too few or too many PopFont()
    5249    IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
    5250 }
    5251 
    5252 enum ImGuiPopupPositionPolicy
    5253 {
    5254    ImGuiPopupPositionPolicy_Default,
    5255    ImGuiPopupPositionPolicy_ComboBox
     4879    EndChild();
     4880}
     4881
     4882static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
     4883{
     4884    window->SetWindowPosAllowFlags       = enabled ? (window->SetWindowPosAllowFlags       | flags) : (window->SetWindowPosAllowFlags       & ~flags);
     4885    window->SetWindowSizeAllowFlags      = enabled ? (window->SetWindowSizeAllowFlags      | flags) : (window->SetWindowSizeAllowFlags      & ~flags);
     4886    window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
     4887}
     4888
     4889ImGuiWindow* ImGui::FindWindowByID(ImGuiID id)
     4890{
     4891    ImGuiContext& g = *GImGui;
     4892    return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
     4893}
     4894
     4895ImGuiWindow* ImGui::FindWindowByName(const char* name)
     4896{
     4897    ImGuiID id = ImHashStr(name);
     4898    return FindWindowByID(id);
     4899}
     4900
     4901static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)
     4902{
     4903    window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y));
     4904    if (settings->Size.x > 0 && settings->Size.y > 0)
     4905        window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y));
     4906    window->Collapsed = settings->Collapsed;
     4907}
     4908
     4909static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
     4910{
     4911    ImGuiContext& g = *GImGui;
     4912    //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
     4913
     4914    // Create window the first time
     4915    ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
     4916    window->Flags = flags;
     4917    g.WindowsById.SetVoidPtr(window->ID, window);
     4918
     4919    // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
     4920    window->Pos = ImVec2(60, 60);
     4921
     4922    // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
     4923    if (!(flags & ImGuiWindowFlags_NoSavedSettings))
     4924        if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
     4925        {
     4926            // Retrieve settings from .ini file
     4927            window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
     4928            SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
     4929            ApplyWindowSettings(window, settings);
     4930        }
     4931    window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
     4932
     4933    if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
     4934    {
     4935        window->AutoFitFramesX = window->AutoFitFramesY = 2;
     4936        window->AutoFitOnlyGrows = false;
     4937    }
     4938    else
     4939    {
     4940        if (window->Size.x <= 0.0f)
     4941            window->AutoFitFramesX = 2;
     4942        if (window->Size.y <= 0.0f)
     4943            window->AutoFitFramesY = 2;
     4944        window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
     4945    }
     4946
     4947    g.WindowsFocusOrder.push_back(window);
     4948    if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
     4949        g.Windows.push_front(window); // Quite slow but rare and only once
     4950    else
     4951        g.Windows.push_back(window);
     4952    return window;
     4953}
     4954
     4955static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
     4956{
     4957    ImGuiContext& g = *GImGui;
     4958    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
     4959    {
     4960        // Using -1,-1 on either X/Y axis to preserve the current size.
     4961        ImRect cr = g.NextWindowData.SizeConstraintRect;
     4962        new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
     4963        new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
     4964        if (g.NextWindowData.SizeCallback)
     4965        {
     4966            ImGuiSizeCallbackData data;
     4967            data.UserData = g.NextWindowData.SizeCallbackUserData;
     4968            data.Pos = window->Pos;
     4969            data.CurrentSize = window->SizeFull;
     4970            data.DesiredSize = new_size;
     4971            g.NextWindowData.SizeCallback(&data);
     4972            new_size = data.DesiredSize;
     4973        }
     4974        new_size.x = IM_FLOOR(new_size.x);
     4975        new_size.y = IM_FLOOR(new_size.y);
     4976    }
     4977
     4978    // Minimum size
     4979    if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
     4980    {
     4981        ImGuiWindow* window_for_height = window;
     4982        new_size = ImMax(new_size, g.Style.WindowMinSize);
     4983        new_size.y = ImMax(new_size.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
     4984    }
     4985    return new_size;
     4986}
     4987
     4988static ImVec2 CalcWindowContentSize(ImGuiWindow* window)
     4989{
     4990    if (window->Collapsed)
     4991        if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
     4992            return window->ContentSize;
     4993    if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
     4994        return window->ContentSize;
     4995
     4996    ImVec2 sz;
     4997    sz.x = IM_FLOOR((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
     4998    sz.y = IM_FLOOR((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
     4999    return sz;
     5000}
     5001
     5002static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)
     5003{
     5004    ImGuiContext& g = *GImGui;
     5005    ImGuiStyle& style = g.Style;
     5006    ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight());
     5007    ImVec2 size_pad = window->WindowPadding * 2.0f;
     5008    ImVec2 size_desired = size_contents + size_pad + size_decorations;
     5009    if (window->Flags & ImGuiWindowFlags_Tooltip)
     5010    {
     5011        // Tooltip always resize
     5012        return size_desired;
     5013    }
     5014    else
     5015    {
     5016        // Maximum window size is determined by the viewport size or monitor size
     5017        const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
     5018        const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
     5019        ImVec2 size_min = style.WindowMinSize;
     5020        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)
     5021            size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
     5022        ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
     5023
     5024        // When the window cannot fit all contents (either because of constraints, either because screen is too small),
     5025        // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
     5026        ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
     5027        bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
     5028        bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
     5029        if (will_have_scrollbar_x)
     5030            size_auto_fit.y += style.ScrollbarSize;
     5031        if (will_have_scrollbar_y)
     5032            size_auto_fit.x += style.ScrollbarSize;
     5033        return size_auto_fit;
     5034    }
     5035}
     5036
     5037ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window)
     5038{
     5039    ImVec2 size_contents = CalcWindowContentSize(window);
     5040    ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents);
     5041    ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);
     5042    return size_final;
     5043}
     5044
     5045static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
     5046{
     5047    if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
     5048        return ImGuiCol_PopupBg;
     5049    if (flags & ImGuiWindowFlags_ChildWindow)
     5050        return ImGuiCol_ChildBg;
     5051    return ImGuiCol_WindowBg;
     5052}
     5053
     5054static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
     5055{
     5056    ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm);                // Expected window upper-left
     5057    ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
     5058    ImVec2 size_expected = pos_max - pos_min;
     5059    ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);
     5060    *out_pos = pos_min;
     5061    if (corner_norm.x == 0.0f)
     5062        out_pos->x -= (size_constrained.x - size_expected.x);
     5063    if (corner_norm.y == 0.0f)
     5064        out_pos->y -= (size_constrained.y - size_expected.y);
     5065    *out_size = size_constrained;
     5066}
     5067
     5068struct ImGuiResizeGripDef
     5069{
     5070    ImVec2  CornerPosN;
     5071    ImVec2  InnerDir;
     5072    int     AngleMin12, AngleMax12;
    52565073};
    52575074
    5258 static ImRect FindAllowedExtentRectForWindow(ImGuiWindow*)
    5259 {
    5260    ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding;
    5261    ImRect r_screen = GetViewportRect();
    5262    r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
    5263    return r_screen;
    5264 }
    5265 
    5266 // 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.)
    5267 // 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.
    5268 static ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy = ImGuiPopupPositionPolicy_Default)
    5269 {
    5270    ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
    5271    //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
    5272    //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
    5273 
    5274    // Combo Box policy (we want a connecting edge)
    5275    if (policy == ImGuiPopupPositionPolicy_ComboBox)
    5276    {
    5277       const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };
    5278       for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
    5279       {
    5280          const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
    5281          if (n != -1 && dir == *last_dir) // Already tried this direction?
    5282             continue;
    5283          ImVec2 pos;
    5284          if (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default)
    5285          if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
    5286          if (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
    5287          if (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
    5288          if (!r_outer.Contains(ImRect(pos, pos + size)))
    5289             continue;
    5290          *last_dir = dir;
    5291          return pos;
    5292       }
    5293    }
    5294 
    5295    // Default popup policy
    5296    const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
    5297    for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
    5298    {
    5299       const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
    5300       if (n != -1 && dir == *last_dir) // Already tried this direction?
    5301          continue;
    5302       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);
    5303       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);
    5304       if (avail_w < size.x || avail_h < size.y)
    5305          continue;
    5306       ImVec2 pos;
    5307       pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
    5308       pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
    5309       *last_dir = dir;
    5310       return pos;
    5311    }
    5312 
    5313    // Fallback, try to keep within display
    5314    *last_dir = ImGuiDir_None;
    5315    ImVec2 pos = ref_pos;
    5316    pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
    5317    pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
    5318    return pos;
    5319 }
    5320 
    5321 static ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window)
    5322 {
    5323    ImGuiContext& g = *GImGui;
    5324 
    5325    ImRect r_outer = FindAllowedExtentRectForWindow(window);
    5326    if (window->Flags & ImGuiWindowFlags_ChildMenu)
    5327    {
    5328       // Child menus typically request _any_ position within the parent menu item, and then our FindBestWindowPosForPopup() function will move the new menu outside the parent bounds.
    5329       // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
    5330       IM_ASSERT(g.CurrentWindow == window);
    5331       ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
    5332       float horizontal_overlap = g.Style.ItemSpacing.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).
    5333       ImRect r_avoid;
    5334       if (parent_window->DC.MenuBarAppending)
    5335          r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight());
    5336       else
    5337          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);
    5338       return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
    5339    }
    5340    if (window->Flags & ImGuiWindowFlags_Popup)
    5341    {
    5342       ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
    5343       return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
    5344    }
    5345    if (window->Flags & ImGuiWindowFlags_Tooltip)
    5346    {
    5347       // Position tooltip (always follows mouse)
    5348       float sc = g.Style.MouseCursorScale;
    5349       ImVec2 ref_pos = NavCalcPreferredRefPos();
    5350       ImRect r_avoid;
    5351       if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))
    5352          r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
    5353       else
    5354          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.
    5355       ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
    5356       if (window->AutoPosLastDirection == ImGuiDir_None)
    5357          pos = ref_pos + ImVec2(2, 2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
    5358       return pos;
    5359    }
    5360    IM_ASSERT(0);
    5361    return window->Pos;
    5362 }
    5363 
    5364 static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
    5365 {
    5366    window->SetWindowPosAllowFlags = enabled ? (window->SetWindowPosAllowFlags | flags) : (window->SetWindowPosAllowFlags       & ~flags);
    5367    window->SetWindowSizeAllowFlags = enabled ? (window->SetWindowSizeAllowFlags | flags) : (window->SetWindowSizeAllowFlags      & ~flags);
    5368    window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
    5369 }
    5370 
    5371 ImGuiWindow* ImGui::FindWindowByName(const char* name)
    5372 {
    5373    ImGuiContext& g = *GImGui;
    5374    ImGuiID id = ImHash(name, 0);
    5375    return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
    5376 }
    5377 
    5378 static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags)
    5379 {
    5380    ImGuiContext& g = *GImGui;
    5381 
    5382    // Create window the first time
    5383    ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
    5384    window->Flags = flags;
    5385    g.WindowsById.SetVoidPtr(window->ID, window);
    5386 
    5387    // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
    5388    window->Pos = ImVec2(60, 60);
    5389 
    5390    // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
    5391    if (!(flags & ImGuiWindowFlags_NoSavedSettings))
    5392    {
    5393       // Retrieve settings from .ini file
    5394       if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
    5395       {
    5396          SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
    5397          window->Pos = ImFloor(settings->Pos);
    5398          window->Collapsed = settings->Collapsed;
    5399          if (ImLengthSqr(settings->Size) > 0.00001f)
    5400             size = ImFloor(settings->Size);
    5401       }
    5402    }
    5403    window->Size = window->SizeFull = window->SizeFullAtLastBegin = size;
    5404 
    5405    if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
    5406    {
    5407       window->AutoFitFramesX = window->AutoFitFramesY = 2;
    5408       window->AutoFitOnlyGrows = false;
    5409    }
    5410    else
    5411    {
    5412       if (window->Size.x <= 0.0f)
    5413          window->AutoFitFramesX = 2;
    5414       if (window->Size.y <= 0.0f)
    5415          window->AutoFitFramesY = 2;
    5416       window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
    5417    }
    5418 
    5419    if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
    5420       g.Windows.insert(g.Windows.begin(), window); // Quite slow but rare and only once
    5421    else
    5422       g.Windows.push_back(window);
    5423    return window;
    5424 }
    5425 
    5426 static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
    5427 {
    5428    ImGuiContext& g = *GImGui;
    5429    if (g.NextWindowData.SizeConstraintCond != 0)
    5430    {
    5431       // Using -1,-1 on either X/Y axis to preserve the current size.
    5432       ImRect cr = g.NextWindowData.SizeConstraintRect;
    5433       new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
    5434       new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
    5435       if (g.NextWindowData.SizeCallback)
    5436       {
    5437          ImGuiSizeCallbackData data;
    5438          data.UserData = g.NextWindowData.SizeCallbackUserData;
    5439          data.Pos = window->Pos;
    5440          data.CurrentSize = window->SizeFull;
    5441          data.DesiredSize = new_size;
    5442          g.NextWindowData.SizeCallback(&data);
    5443          new_size = data.DesiredSize;
    5444       }
    5445    }
    5446 
    5447    // Minimum size
    5448    if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
    5449    {
    5450       new_size = ImMax(new_size, g.Style.WindowMinSize);
    5451       new_size.y = ImMax(new_size.y, window->TitleBarHeight() + window->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
    5452    }
    5453    return new_size;
    5454 }
    5455 
    5456 static ImVec2 CalcSizeContents(ImGuiWindow* window)
    5457 {
    5458    ImVec2 sz;
    5459    sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x));
    5460    sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y));
    5461    return sz + window->WindowPadding;
    5462 }
    5463 
    5464 static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
    5465 {
    5466    ImGuiContext& g = *GImGui;
    5467    ImGuiStyle& style = g.Style;
    5468    if (window->Flags & ImGuiWindowFlags_Tooltip)
    5469    {
    5470       // Tooltip always resize
    5471       return size_contents;
    5472    }
    5473    else
    5474    {
    5475       // When the window cannot fit all contents (either because of constraints, either because screen is too small): we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than DisplaySize-WindowPadding.
    5476       ImVec2 size_auto_fit = ImClamp(size_contents, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - g.Style.DisplaySafeAreaPadding * 2.0f));
    5477       ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit);
    5478       if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar))
    5479          size_auto_fit.y += style.ScrollbarSize;
    5480       if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar))
    5481          size_auto_fit.x += style.ScrollbarSize;
    5482       return size_auto_fit;
    5483    }
    5484 }
    5485 
    5486 static float GetScrollMaxX(ImGuiWindow* window)
    5487 {
    5488    return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x));
    5489 }
    5490 
    5491 static float GetScrollMaxY(ImGuiWindow* window)
    5492 {
    5493    return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y));
    5494 }
    5495 
    5496 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
    5497 {
    5498    ImVec2 scroll = window->Scroll;
    5499    float cr_x = window->ScrollTargetCenterRatio.x;
    5500    float cr_y = window->ScrollTargetCenterRatio.y;
    5501    if (window->ScrollTarget.x < FLT_MAX)
    5502       scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
    5503    if (window->ScrollTarget.y < FLT_MAX)
    5504       scroll.y = window->ScrollTarget.y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y);
    5505    scroll = ImMax(scroll, ImVec2(0.0f, 0.0f));
    5506    if (!window->Collapsed && !window->SkipItems)
    5507    {
    5508       scroll.x = ImMin(scroll.x, GetScrollMaxX(window));
    5509       scroll.y = ImMin(scroll.y, GetScrollMaxY(window));
    5510    }
    5511    return scroll;
    5512 }
    5513 
    5514 static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
    5515 {
    5516    if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
    5517       return ImGuiCol_PopupBg;
    5518    if (flags & ImGuiWindowFlags_ChildWindow)
    5519       return ImGuiCol_ChildBg;
    5520    return ImGuiCol_WindowBg;
    5521 }
    5522 
    5523 static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
    5524 {
    5525    ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm);                // Expected window upper-left
    5526    ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
    5527    ImVec2 size_expected = pos_max - pos_min;
    5528    ImVec2 size_constrained = CalcSizeAfterConstraint(window, size_expected);
    5529    *out_pos = pos_min;
    5530    if (corner_norm.x == 0.0f)
    5531       out_pos->x -= (size_constrained.x - size_expected.x);
    5532    if (corner_norm.y == 0.0f)
    5533       out_pos->y -= (size_constrained.y - size_expected.y);
    5534    *out_size = size_constrained;
    5535 }
    5536 
    5537 struct ImGuiResizeGripDef
    5538 {
    5539    ImVec2  CornerPos;
    5540    ImVec2  InnerDir;
    5541    int     AngleMin12, AngleMax12;
     5075static const ImGuiResizeGripDef resize_grip_def[4] =
     5076{
     5077    { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right
     5078    { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left
     5079    { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused)
     5080    { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }, // Upper-right (Unused)
    55425081};
    55435082
    5544 const ImGuiResizeGripDef resize_grip_def[4] =
    5545 {
    5546    { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right
    5547 { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left
    5548 { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left
    5549 { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right
     5083struct ImGuiResizeBorderDef
     5084{
     5085    ImVec2 InnerDir;
     5086    ImVec2 CornerPosN1, CornerPosN2;
     5087    float  OuterAngle;
    55505088};
    55515089
    5552 static ImRect GetBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
    5553 {
    5554    ImRect rect = window->Rect();
    5555    if (thickness == 0.0f) rect.Max -= ImVec2(1, 1);
    5556    if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y, rect.Max.x - perp_padding, rect.Min.y + thickness);
    5557    if (border_n == 1) return ImRect(rect.Max.x - thickness, rect.Min.y + perp_padding, rect.Max.x, rect.Max.y - perp_padding);
    5558    if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness, rect.Max.x - perp_padding, rect.Max.y);
    5559    if (border_n == 3) return ImRect(rect.Min.x, rect.Min.y + perp_padding, rect.Min.x + thickness, rect.Max.y - perp_padding);
    5560    IM_ASSERT(0);
    5561    return ImRect();
     5090static const ImGuiResizeBorderDef resize_border_def[4] =
     5091{
     5092    { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Top
     5093    { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right
     5094    { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }, // Bottom
     5095    { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f } // Left
     5096};
     5097
     5098static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
     5099{
     5100    ImRect rect = window->Rect();
     5101    if (thickness == 0.0f) rect.Max -= ImVec2(1, 1);
     5102    if (border_n == 0) { return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness,    rect.Max.x - perp_padding, rect.Min.y + thickness);    } // Top
     5103    if (border_n == 1) { return ImRect(rect.Max.x - thickness,    rect.Min.y + perp_padding, rect.Max.x + thickness,    rect.Max.y - perp_padding); } // Right
     5104    if (border_n == 2) { return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness,    rect.Max.x - perp_padding, rect.Max.y + thickness);    } // Bottom
     5105    if (border_n == 3) { return ImRect(rect.Min.x - thickness,    rect.Min.y + perp_padding, rect.Min.x + thickness,    rect.Max.y - perp_padding); } // Left
     5106    IM_ASSERT(0);
     5107    return ImRect();
     5108}
     5109
     5110// 0..3: corners (Lower-right, Lower-left, Unused, Unused)
     5111// 4..7: borders (Top, Right, Bottom, Left)
     5112ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n)
     5113{
     5114    IM_ASSERT(n >= 0 && n <= 7);
     5115    ImGuiID id = window->ID;
     5116    id = ImHashStr("#RESIZE", 0, id);
     5117    id = ImHashData(&n, sizeof(int), id);
     5118    return id;
    55625119}
    55635120
    55645121// Handle resize for: Resize Grips, Borders, Gamepad
    5565 static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
    5566 {
    5567    ImGuiContext& g = *GImGui;
    5568    ImGuiWindowFlags flags = window->Flags;
    5569    if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
    5570       return;
    5571 
    5572    const int resize_border_count = (flags & ImGuiWindowFlags_ResizeFromAnySide) ? 4 : 0;
    5573    const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
    5574    const float grip_hover_size = (float)(int)(grip_draw_size * 0.75f);
    5575 
    5576    ImVec2 pos_target(FLT_MAX, FLT_MAX);
    5577    ImVec2 size_target(FLT_MAX, FLT_MAX);
    5578 
    5579    // Manual resize grips
    5580    PushID("#RESIZE");
    5581    for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
    5582    {
    5583       const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
    5584       const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
    5585 
    5586       // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
    5587       ImRect resize_rect(corner, corner + grip.InnerDir * grip_hover_size);
    5588       if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
    5589       if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
    5590       bool hovered, held;
    5591       ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
    5592       if (hovered || held)
    5593          g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
    5594 
    5595       if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
    5596       {
    5597          // Manual auto-fit when double-clicking
    5598          size_target = CalcSizeAfterConstraint(window, size_auto_fit);
    5599          ClearActiveID();
    5600       }
    5601       else if (held)
    5602       {
    5603          // Resize from any of the four corners
    5604          // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
    5605          ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize() * grip.CornerPos; // Corner of the window corresponding to our corner grip
    5606          CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPos, &pos_target, &size_target);
    5607       }
    5608       if (resize_grip_n == 0 || held || hovered)
    5609          resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
    5610    }
    5611    for (int border_n = 0; border_n < resize_border_count; border_n++)
    5612    {
    5613       const float BORDER_SIZE = 5.0f;          // FIXME: Only works _inside_ window because of HoveredWindow check.
    5614       const float BORDER_APPEAR_TIMER = 0.05f; // Reduce visual noise
    5615       bool hovered, held;
    5616       ImRect border_rect = GetBorderRect(window, border_n, grip_hover_size, BORDER_SIZE);
    5617       ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
    5618       if ((hovered && g.HoveredIdTimer > BORDER_APPEAR_TIMER) || held)
    5619       {
    5620          g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
    5621          if (held) *border_held = border_n;
    5622       }
    5623       if (held)
    5624       {
    5625          ImVec2 border_target = window->Pos;
    5626          ImVec2 border_posn;
    5627          if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y); }
    5628          if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + BORDER_SIZE); }
    5629          if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + BORDER_SIZE); }
    5630          if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x); }
    5631          CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
    5632       }
    5633    }
    5634    PopID();
    5635 
    5636    // Navigation resize (keyboard/gamepad)
    5637    if (g.NavWindowingTarget == window)
    5638    {
    5639       ImVec2 nav_resize_delta;
    5640       if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift)
    5641          nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
    5642       if (g.NavInputSource == ImGuiInputSource_NavGamepad)
    5643          nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down);
    5644       if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
    5645       {
    5646          const float NAV_RESIZE_SPEED = 600.0f;
    5647          nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
    5648          g.NavWindowingToggleLayer = false;
    5649          g.NavDisableMouseHover = true;
    5650          resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
    5651          // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
    5652          size_target = CalcSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
    5653       }
    5654    }
    5655 
    5656    // Apply back modified position/size to window
    5657    if (size_target.x != FLT_MAX)
    5658    {
    5659       window->SizeFull = size_target;
    5660       MarkIniSettingsDirty(window);
    5661    }
    5662    if (pos_target.x != FLT_MAX)
    5663    {
    5664       window->Pos = ImFloor(pos_target);
    5665       MarkIniSettingsDirty(window);
    5666    }
    5667 
    5668    window->Size = window->SizeFull;
    5669 }
    5670 
    5671 // Push a new ImGui window to add widgets to.
     5122// Return true when using auto-fit (double click on resize grip)
     5123static 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)
     5124{
     5125    ImGuiContext& g = *GImGui;
     5126    ImGuiWindowFlags flags = window->Flags;
     5127
     5128    if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
     5129        return false;
     5130    if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
     5131        return false;
     5132
     5133    bool ret_auto_fit = false;
     5134    const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
     5135    const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
     5136    const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);
     5137    const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f;
     5138
     5139    ImVec2 pos_target(FLT_MAX, FLT_MAX);
     5140    ImVec2 size_target(FLT_MAX, FLT_MAX);
     5141
     5142    // Resize grips and borders are on layer 1
     5143    window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
     5144
     5145    // Manual resize grips
     5146    PushID("#RESIZE");
     5147    for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
     5148    {
     5149        const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
     5150        const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
     5151
     5152        // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
     5153        ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
     5154        if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
     5155        if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
     5156        bool hovered, held;
     5157        ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
     5158        //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
     5159        if (hovered || held)
     5160            g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
     5161
     5162        if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
     5163        {
     5164            // Manual auto-fit when double-clicking
     5165            size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
     5166            ret_auto_fit = true;
     5167            ClearActiveID();
     5168        }
     5169        else if (held)
     5170        {
     5171            // Resize from any of the four corners
     5172            // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
     5173            ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip
     5174            ImVec2 clamp_min = ImVec2(grip.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, grip.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
     5175            ImVec2 clamp_max = ImVec2(grip.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, grip.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
     5176            corner_target = ImClamp(corner_target, clamp_min, clamp_max);
     5177            CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target);
     5178        }
     5179        if (resize_grip_n == 0 || held || hovered)
     5180            resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
     5181    }
     5182    for (int border_n = 0; border_n < resize_border_count; border_n++)
     5183    {
     5184        bool hovered, held;
     5185        ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS);
     5186        ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
     5187        //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
     5188        if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
     5189        {
     5190            g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
     5191            if (held)
     5192                *border_held = border_n;
     5193        }
     5194        if (held)
     5195        {
     5196            ImVec2 border_target = window->Pos;
     5197            ImVec2 border_posn;
     5198            if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top
     5199            if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right
     5200            if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom
     5201            if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left
     5202            ImVec2 clamp_min = ImVec2(border_n == 1 ? visibility_rect.Min.x : -FLT_MAX, border_n == 2 ? visibility_rect.Min.y : -FLT_MAX);
     5203            ImVec2 clamp_max = ImVec2(border_n == 3 ? visibility_rect.Max.x : +FLT_MAX, border_n == 0 ? visibility_rect.Max.y : +FLT_MAX);
     5204            border_target = ImClamp(border_target, clamp_min, clamp_max);
     5205            CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
     5206        }
     5207    }
     5208    PopID();
     5209
     5210    // Restore nav layer
     5211    window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
     5212
     5213    // Navigation resize (keyboard/gamepad)
     5214    if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window)
     5215    {
     5216        ImVec2 nav_resize_delta;
     5217        if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift)
     5218            nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
     5219        if (g.NavInputSource == ImGuiInputSource_NavGamepad)
     5220            nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down);
     5221        if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
     5222        {
     5223            const float NAV_RESIZE_SPEED = 600.0f;
     5224            nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
     5225            nav_resize_delta = ImMax(nav_resize_delta, visibility_rect.Min - window->Pos - window->Size);
     5226            g.NavWindowingToggleLayer = false;
     5227            g.NavDisableMouseHover = true;
     5228            resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
     5229            // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
     5230            size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
     5231        }
     5232    }
     5233
     5234    // Apply back modified position/size to window
     5235    if (size_target.x != FLT_MAX)
     5236    {
     5237        window->SizeFull = size_target;
     5238        MarkIniSettingsDirty(window);
     5239    }
     5240    if (pos_target.x != FLT_MAX)
     5241    {
     5242        window->Pos = ImFloor(pos_target);
     5243        MarkIniSettingsDirty(window);
     5244    }
     5245
     5246    window->Size = window->SizeFull;
     5247    return ret_auto_fit;
     5248}
     5249
     5250static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& visibility_rect)
     5251{
     5252    ImGuiContext& g = *GImGui;
     5253    ImVec2 size_for_clamping = window->Size;
     5254    if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
     5255        size_for_clamping.y = window->TitleBarHeight();
     5256    window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
     5257}
     5258
     5259static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
     5260{
     5261    ImGuiContext& g = *GImGui;
     5262    float rounding = window->WindowRounding;
     5263    float border_size = window->WindowBorderSize;
     5264    if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))
     5265        window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
     5266
     5267    int border_held = window->ResizeBorderHeld;
     5268    if (border_held != -1)
     5269    {
     5270        const ImGuiResizeBorderDef& def = resize_border_def[border_held];
     5271        ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
     5272        window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI * 0.25f, def.OuterAngle);
     5273        window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI * 0.25f);
     5274        window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual
     5275    }
     5276    if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
     5277    {
     5278        float y = window->Pos.y + window->TitleBarHeight() - 1;
     5279        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);
     5280    }
     5281}
     5282
     5283// Draw background and borders
     5284// Draw and handle scrollbars
     5285void 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)
     5286{
     5287    ImGuiContext& g = *GImGui;
     5288    ImGuiStyle& style = g.Style;
     5289    ImGuiWindowFlags flags = window->Flags;
     5290
     5291    // Ensure that ScrollBar doesn't read last frame's SkipItems
     5292    IM_ASSERT(window->BeginCount == 0);
     5293    window->SkipItems = false;
     5294
     5295    // Draw window + handle manual resize
     5296    // 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.
     5297    const float window_rounding = window->WindowRounding;
     5298    const float window_border_size = window->WindowBorderSize;
     5299    if (window->Collapsed)
     5300    {
     5301        // Title bar only
     5302        float backup_border_size = style.FrameBorderSize;
     5303        g.Style.FrameBorderSize = window->WindowBorderSize;
     5304        ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
     5305        RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
     5306        g.Style.FrameBorderSize = backup_border_size;
     5307    }
     5308    else
     5309    {
     5310        // Window background
     5311        if (!(flags & ImGuiWindowFlags_NoBackground))
     5312        {
     5313            ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
     5314            bool override_alpha = false;
     5315            float alpha = 1.0f;
     5316            if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
     5317            {
     5318                alpha = g.NextWindowData.BgAlphaVal;
     5319                override_alpha = true;
     5320            }
     5321            if (override_alpha)
     5322                bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
     5323            window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
     5324        }
     5325
     5326        // Title bar
     5327        if (!(flags & ImGuiWindowFlags_NoTitleBar))
     5328        {
     5329            ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
     5330            window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
     5331        }
     5332
     5333        // Menu bar
     5334        if (flags & ImGuiWindowFlags_MenuBar)
     5335        {
     5336            ImRect menu_bar_rect = window->MenuBarRect();
     5337            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.
     5338            window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
     5339            if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
     5340                window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
     5341        }
     5342
     5343        // Scrollbars
     5344        if (window->ScrollbarX)
     5345            Scrollbar(ImGuiAxis_X);
     5346        if (window->ScrollbarY)
     5347            Scrollbar(ImGuiAxis_Y);
     5348
     5349        // Render resize grips (after their input handling so we don't have a frame of latency)
     5350        if (!(flags & ImGuiWindowFlags_NoResize))
     5351        {
     5352            for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
     5353            {
     5354                const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
     5355                const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
     5356                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)));
     5357                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)));
     5358                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);
     5359                window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
     5360            }
     5361        }
     5362
     5363        // Borders
     5364        RenderWindowOuterBorders(window);
     5365    }
     5366}
     5367
     5368// Render title text, collapse button, close button
     5369void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
     5370{
     5371    ImGuiContext& g = *GImGui;
     5372    ImGuiStyle& style = g.Style;
     5373    ImGuiWindowFlags flags = window->Flags;
     5374
     5375    const bool has_close_button = (p_open != NULL);
     5376    const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
     5377
     5378    // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
     5379    const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
     5380    window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
     5381    window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
     5382
     5383    // Layout buttons
     5384    // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
     5385    float pad_l = style.FramePadding.x;
     5386    float pad_r = style.FramePadding.x;
     5387    float button_sz = g.FontSize;
     5388    ImVec2 close_button_pos;
     5389    ImVec2 collapse_button_pos;
     5390    if (has_close_button)
     5391    {
     5392        pad_r += button_sz;
     5393        close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
     5394    }
     5395    if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
     5396    {
     5397        pad_r += button_sz;
     5398        collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
     5399    }
     5400    if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
     5401    {
     5402        collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
     5403        pad_l += button_sz;
     5404    }
     5405
     5406    // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
     5407    if (has_collapse_button)
     5408        if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos))
     5409            window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
     5410
     5411    // Close button
     5412    if (has_close_button)
     5413        if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
     5414            *p_open = false;
     5415
     5416    window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
     5417    window->DC.ItemFlags = item_flags_backup;
     5418
     5419    // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
     5420    // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
     5421    const char* UNSAVED_DOCUMENT_MARKER = "*";
     5422    const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
     5423    const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
     5424
     5425    // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
     5426    // while uncentered title text will still reach edges correct.
     5427    if (pad_l > style.FramePadding.x)
     5428        pad_l += g.Style.ItemInnerSpacing.x;
     5429    if (pad_r > style.FramePadding.x)
     5430        pad_r += g.Style.ItemInnerSpacing.x;
     5431    if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
     5432    {
     5433        float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
     5434        float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
     5435        pad_l = ImMax(pad_l, pad_extend * centerness);
     5436        pad_r = ImMax(pad_r, pad_extend * centerness);
     5437    }
     5438
     5439    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);
     5440    ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y);
     5441    //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
     5442    RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
     5443    if (flags & ImGuiWindowFlags_UnsavedDocument)
     5444    {
     5445        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);
     5446        ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f));
     5447        RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
     5448    }
     5449}
     5450
     5451void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
     5452{
     5453    window->ParentWindow = parent_window;
     5454    window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
     5455    if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
     5456        window->RootWindow = parent_window->RootWindow;
     5457    if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
     5458        window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
     5459    while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
     5460    {
     5461        IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
     5462        window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
     5463    }
     5464}
     5465
     5466// Push a new Dear ImGui window to add widgets to.
    56725467// - 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.
    56735468// - Begin/End can be called multiple times during the frame with the same window name to append content.
     
    56785473bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
    56795474{
    5680    ImGuiContext& g = *GImGui;
    5681    const ImGuiStyle& style = g.Style;
    5682    IM_ASSERT(name != NULL);                        // Window name required
    5683    IM_ASSERT(g.Initialized);                       // Forgot to call ImGui::NewFrame()
    5684    IM_ASSERT(g.FrameCountEnded != g.FrameCount);   // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
    5685 
    5686                                                    // Find or create
    5687    ImGuiWindow* window = FindWindowByName(name);
    5688    const bool window_just_created = (window == NULL);
    5689    if (window_just_created)
    5690    {
    5691       ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
    5692       window = CreateNewWindow(name, size_on_first_use, flags);
    5693    }
    5694 
    5695    // Automatically disable manual moving/resizing when NoInputs is set
    5696    if (flags & ImGuiWindowFlags_NoInputs)
    5697       flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
    5698 
    5699    if (flags & ImGuiWindowFlags_NavFlattened)
    5700       IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
    5701 
    5702    const int current_frame = g.FrameCount;
    5703    const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
    5704    if (first_begin_of_the_frame)
    5705       window->Flags = (ImGuiWindowFlags)flags;
    5706    else
    5707       flags = window->Flags;
    5708 
    5709    // Update the Appearing flag
    5710    bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1);   // Not using !WasActive because the implicit "Debug" window would always toggle off->on
    5711    const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFrames > 0);
    5712    if (flags & ImGuiWindowFlags_Popup)
    5713    {
    5714       ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
    5715       window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
    5716       window_just_activated_by_user |= (window != popup_ref.Window);
    5717    }
    5718    window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
    5719    window->CloseButton = (p_open != NULL);
    5720    if (window->Appearing)
    5721       SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
    5722 
    5723    // 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
    5724    ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
    5725    ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
    5726    IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
    5727 
    5728    // Add to stack
    5729    g.CurrentWindowStack.push_back(window);
    5730    SetCurrentWindow(window);
    5731    CheckStacksSize(window, true);
    5732    if (flags & ImGuiWindowFlags_Popup)
    5733    {
    5734       ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.CurrentPopupStack.Size];
    5735       popup_ref.Window = window;
    5736       g.CurrentPopupStack.push_back(popup_ref);
    5737       window->PopupId = popup_ref.PopupId;
    5738    }
    5739 
    5740    if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow))
    5741       window->NavLastIds[0] = 0;
    5742 
    5743    // Process SetNextWindow***() calls
    5744    bool window_pos_set_by_api = false;
    5745    bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
    5746    if (g.NextWindowData.PosCond)
    5747    {
    5748       window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
    5749       if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
    5750       {
    5751          // May be processed on the next frame if this is our first frame and we are measuring size
    5752          // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
    5753          window->SetWindowPosVal = g.NextWindowData.PosVal;
    5754          window->SetWindowPosPivot = g.NextWindowData.PosPivotVal;
    5755          window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
    5756       }
    5757       else
    5758       {
    5759          SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
    5760       }
    5761    }
    5762    if (g.NextWindowData.SizeCond)
    5763    {
    5764       window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
    5765       window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
    5766       SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
    5767    }
    5768    if (g.NextWindowData.ContentSizeCond)
    5769    {
    5770       // Adjust passed "client size" to become a "window size"
    5771       window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal;
    5772       if (window->SizeContentsExplicit.y != 0.0f)
    5773          window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight();
    5774    }
    5775    else if (first_begin_of_the_frame)
    5776    {
    5777       window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
    5778    }
    5779    if (g.NextWindowData.CollapsedCond)
    5780       SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
    5781    if (g.NextWindowData.FocusCond)
    5782       FocusWindow(window);
    5783    if (window->Appearing)
    5784       SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
    5785 
    5786    // When reusing window again multiple times a frame, just append content (don't need to setup again)
    5787    if (first_begin_of_the_frame)
    5788    {
    5789       const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
    5790 
    5791                                                                                                                          // Initialize
    5792       window->ParentWindow = parent_window;
    5793       window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForTabbing = window->RootWindowForNav = window;
    5794       if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !window_is_child_tooltip)
    5795          window->RootWindow = parent_window->RootWindow;
    5796       if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
    5797          window->RootWindowForTitleBarHighlight = window->RootWindowForTabbing = parent_window->RootWindowForTitleBarHighlight; // Same value in master branch, will differ for docking
    5798       while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
    5799          window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
    5800 
    5801       window->Active = true;
    5802       window->BeginOrderWithinParent = 0;
    5803       window->BeginOrderWithinContext = g.WindowsActiveCount++;
    5804       window->BeginCount = 0;
    5805       window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
    5806       window->LastFrameActive = current_frame;
    5807       window->IDStack.resize(1);
    5808 
    5809       // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
    5810 
    5811       // Update contents size from last frame for auto-fitting (or use explicit size)
    5812       window->SizeContents = CalcSizeContents(window);
    5813       if (window->HiddenFrames > 0)
    5814          window->HiddenFrames--;
    5815 
    5816       // Hide new windows for one frame until they calculate their size
    5817       if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
    5818          window->HiddenFrames = 1;
    5819 
    5820       // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
    5821       // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
    5822       if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
    5823       {
    5824          window->HiddenFrames = 1;
    5825          if (flags & ImGuiWindowFlags_AlwaysAutoResize)
    5826          {
     5475    ImGuiContext& g = *GImGui;
     5476    const ImGuiStyle& style = g.Style;
     5477    IM_ASSERT(name != NULL && name[0] != '\0');     // Window name required
     5478    IM_ASSERT(g.WithinFrameScope);                  // Forgot to call ImGui::NewFrame()
     5479    IM_ASSERT(g.FrameCountEnded != g.FrameCount);   // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
     5480
     5481    // Find or create
     5482    ImGuiWindow* window = FindWindowByName(name);
     5483    const bool window_just_created = (window == NULL);
     5484    if (window_just_created)
     5485        window = CreateNewWindow(name, flags);
     5486
     5487    // Automatically disable manual moving/resizing when NoInputs is set
     5488    if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
     5489        flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
     5490
     5491    if (flags & ImGuiWindowFlags_NavFlattened)
     5492        IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
     5493
     5494    const int current_frame = g.FrameCount;
     5495    const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
     5496    window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);
     5497
     5498    // Update the Appearing flag
     5499    bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1);   // Not using !WasActive because the implicit "Debug" window would always toggle off->on
     5500    const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
     5501    if (flags & ImGuiWindowFlags_Popup)
     5502    {
     5503        ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
     5504        window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
     5505        window_just_activated_by_user |= (window != popup_ref.Window);
     5506    }
     5507    window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
     5508    if (window->Appearing)
     5509        SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
     5510
     5511    // Update Flags, LastFrameActive, BeginOrderXXX fields
     5512    if (first_begin_of_the_frame)
     5513    {
     5514        window->Flags = (ImGuiWindowFlags)flags;
     5515        window->LastFrameActive = current_frame;
     5516        window->LastTimeActive = (float)g.Time;
     5517        window->BeginOrderWithinParent = 0;
     5518        window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
     5519    }
     5520    else
     5521    {
     5522        flags = window->Flags;
     5523    }
     5524
     5525    // 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
     5526    ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
     5527    ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
     5528    IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
     5529
     5530    // We allow window memory to be compacted so recreate the base stack when needed.
     5531    if (window->IDStack.Size == 0)
     5532        window->IDStack.push_back(window->ID);
     5533
     5534    // Add to stack
     5535    // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
     5536    g.CurrentWindowStack.push_back(window);
     5537    g.CurrentWindow = NULL;
     5538    ErrorCheckBeginEndCompareStacksSize(window, true);
     5539    if (flags & ImGuiWindowFlags_Popup)
     5540    {
     5541        ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
     5542        popup_ref.Window = window;
     5543        g.BeginPopupStack.push_back(popup_ref);
     5544        window->PopupId = popup_ref.PopupId;
     5545    }
     5546
     5547    if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow))
     5548        window->NavLastIds[0] = 0;
     5549
     5550    // Update ->RootWindow and others pointers (before any possible call to FocusWindow)
     5551    if (first_begin_of_the_frame)
     5552        UpdateWindowParentAndRootLinks(window, flags, parent_window);
     5553
     5554    // Process SetNextWindow***() calls
     5555    // (FIXME: Consider splitting the HasXXX flags into X/Y components
     5556    bool window_pos_set_by_api = false;
     5557    bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
     5558    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)
     5559    {
     5560        window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
     5561        if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
     5562        {
     5563            // May be processed on the next frame if this is our first frame and we are measuring size
     5564            // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
     5565            window->SetWindowPosVal = g.NextWindowData.PosVal;
     5566            window->SetWindowPosPivot = g.NextWindowData.PosPivotVal;
     5567            window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
     5568        }
     5569        else
     5570        {
     5571            SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
     5572        }
     5573    }
     5574    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)
     5575    {
     5576        window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
     5577        window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
     5578        SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
     5579    }
     5580    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll)
     5581    {
     5582        if (g.NextWindowData.ScrollVal.x >= 0.0f)
     5583        {
     5584            window->ScrollTarget.x = g.NextWindowData.ScrollVal.x;
     5585            window->ScrollTargetCenterRatio.x = 0.0f;
     5586        }
     5587        if (g.NextWindowData.ScrollVal.y >= 0.0f)
     5588        {
     5589            window->ScrollTarget.y = g.NextWindowData.ScrollVal.y;
     5590            window->ScrollTargetCenterRatio.y = 0.0f;
     5591        }
     5592    }
     5593    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)
     5594        window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal;
     5595    else if (first_begin_of_the_frame)
     5596        window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
     5597    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)
     5598        SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
     5599    if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
     5600        FocusWindow(window);
     5601    if (window->Appearing)
     5602        SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
     5603
     5604    // When reusing window again multiple times a frame, just append content (don't need to setup again)
     5605    if (first_begin_of_the_frame)
     5606    {
     5607        // Initialize
     5608        const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
     5609        window->Active = true;
     5610        window->HasCloseButton = (p_open != NULL);
     5611        window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
     5612        window->IDStack.resize(1);
     5613        window->DrawList->_ResetForNewFrame();
     5614
     5615        // Restore buffer capacity when woken from a compacted state, to avoid
     5616        if (window->MemoryCompacted)
     5617            GcAwakeTransientWindowBuffers(window);
     5618
     5619        // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
     5620        // 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.
     5621        bool window_title_visible_elsewhere = false;
     5622        if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0)   // Window titles visible when using CTRL+TAB
     5623            window_title_visible_elsewhere = true;
     5624        if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
     5625        {
     5626            size_t buf_len = (size_t)window->NameBufLen;
     5627            window->Name = ImStrdupcpy(window->Name, &buf_len, name);
     5628            window->NameBufLen = (int)buf_len;
     5629        }
     5630
     5631        // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
     5632
     5633        // Update contents size from last frame for auto-fitting (or use explicit size)
     5634        window->ContentSize = CalcWindowContentSize(window);
     5635        if (window->HiddenFramesCanSkipItems > 0)
     5636            window->HiddenFramesCanSkipItems--;
     5637        if (window->HiddenFramesCannotSkipItems > 0)
     5638            window->HiddenFramesCannotSkipItems--;
     5639
     5640        // Hide new windows for one frame until they calculate their size
     5641        if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
     5642            window->HiddenFramesCannotSkipItems = 1;
     5643
     5644        // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
     5645        // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
     5646        if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
     5647        {
     5648            window->HiddenFramesCannotSkipItems = 1;
     5649            if (flags & ImGuiWindowFlags_AlwaysAutoResize)
     5650            {
     5651                if (!window_size_x_set_by_api)
     5652                    window->Size.x = window->SizeFull.x = 0.f;
     5653                if (!window_size_y_set_by_api)
     5654                    window->Size.y = window->SizeFull.y = 0.f;
     5655                window->ContentSize = ImVec2(0.f, 0.f);
     5656            }
     5657        }
     5658
     5659        // SELECT VIEWPORT
     5660        // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style)
     5661        SetCurrentWindow(window);
     5662
     5663        // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)
     5664
     5665        if (flags & ImGuiWindowFlags_ChildWindow)
     5666            window->WindowBorderSize = style.ChildBorderSize;
     5667        else
     5668            window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
     5669        window->WindowPadding = style.WindowPadding;
     5670        if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)
     5671            window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
     5672
     5673        // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size.
     5674        window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
     5675        window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
     5676
     5677        // Collapse window by double-clicking on title bar
     5678        // 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
     5679        if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
     5680        {
     5681            // 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.
     5682            ImRect title_bar_rect = window->TitleBarRect();
     5683            if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])
     5684                window->WantCollapseToggle = true;
     5685            if (window->WantCollapseToggle)
     5686            {
     5687                window->Collapsed = !window->Collapsed;
     5688                MarkIniSettingsDirty(window);
     5689                FocusWindow(window);
     5690            }
     5691        }
     5692        else
     5693        {
     5694            window->Collapsed = false;
     5695        }
     5696        window->WantCollapseToggle = false;
     5697
     5698        // SIZE
     5699
     5700        // Calculate auto-fit size, handle automatic resize
     5701        const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSize);
     5702        bool use_current_size_for_scrollbar_x = window_just_created;
     5703        bool use_current_size_for_scrollbar_y = window_just_created;
     5704        if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
     5705        {
     5706            // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
    58275707            if (!window_size_x_set_by_api)
    5828                window->Size.x = window->SizeFull.x = 0.f;
     5708            {
     5709                window->SizeFull.x = size_auto_fit.x;
     5710                use_current_size_for_scrollbar_x = true;
     5711            }
    58295712            if (!window_size_y_set_by_api)
    5830                window->Size.y = window->SizeFull.y = 0.f;
    5831             window->SizeContents = ImVec2(0.f, 0.f);
    5832          }
    5833       }
    5834 
    5835       SetCurrentWindow(window);
    5836 
    5837       // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies)
    5838       window->WindowBorderSize = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildBorderSize : ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
    5839       window->WindowPadding = style.WindowPadding;
    5840       if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)
    5841          window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
    5842       window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
    5843       window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
    5844 
    5845       // Collapse window by double-clicking on title bar
    5846       // 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
    5847       if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
    5848       {
    5849          ImRect title_bar_rect = window->TitleBarRect();
    5850          if (window->CollapseToggleWanted || (g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0]))
    5851          {
    5852             window->Collapsed = !window->Collapsed;
    5853             MarkIniSettingsDirty(window);
     5713            {
     5714                window->SizeFull.y = size_auto_fit.y;
     5715                use_current_size_for_scrollbar_y = true;
     5716            }
     5717        }
     5718        else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
     5719        {
     5720            // Auto-fit may only grow window during the first few frames
     5721            // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
     5722            if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
     5723            {
     5724                window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
     5725                use_current_size_for_scrollbar_x = true;
     5726            }
     5727            if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
     5728            {
     5729                window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
     5730                use_current_size_for_scrollbar_y = true;
     5731            }
     5732            if (!window->Collapsed)
     5733                MarkIniSettingsDirty(window);
     5734        }
     5735
     5736        // Apply minimum/maximum window size constraints and final size
     5737        window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);
     5738        window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
     5739
     5740        // Decoration size
     5741        const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
     5742
     5743        // POSITION
     5744
     5745        // Popup latch its initial position, will position itself when it appears next frame
     5746        if (window_just_activated_by_user)
     5747        {
     5748            window->AutoPosLastDirection = ImGuiDir_None;
     5749            if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos()
     5750                window->Pos = g.BeginPopupStack.back().OpenPopupPos;
     5751        }
     5752
     5753        // Position child window
     5754        if (flags & ImGuiWindowFlags_ChildWindow)
     5755        {
     5756            IM_ASSERT(parent_window && parent_window->Active);
     5757            window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
     5758            parent_window->DC.ChildWindows.push_back(window);
     5759            if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
     5760                window->Pos = parent_window->DC.CursorPos;
     5761        }
     5762
     5763        const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);
     5764        if (window_pos_with_pivot)
     5765            SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering)
     5766        else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
     5767            window->Pos = FindBestWindowPosForPopup(window);
     5768        else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
     5769            window->Pos = FindBestWindowPosForPopup(window);
     5770        else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
     5771            window->Pos = FindBestWindowPosForPopup(window);
     5772
     5773        // Calculate the range of allowed position for that window (to be movable and visible past safe area padding)
     5774        // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect.
     5775        ImRect viewport_rect(GetViewportRect());
     5776        ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
     5777        ImRect visibility_rect(viewport_rect.Min + visibility_padding, viewport_rect.Max - visibility_padding);
     5778
     5779        // Clamp position/size so window stays visible within its viewport or monitor
     5780        // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
     5781        if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
     5782            if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f)
     5783                ClampWindowRect(window, visibility_rect);
     5784        window->Pos = ImFloor(window->Pos);
     5785
     5786        // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
     5787        // Large values tend to lead to variety of artifacts and are not recommended.
     5788        window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
     5789
     5790        // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts.
     5791        //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar))
     5792        //    window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f);
     5793
     5794        // Apply window focus (new and reactivated windows are moved to front)
     5795        bool want_focus = false;
     5796        if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
     5797        {
     5798            if (flags & ImGuiWindowFlags_Popup)
     5799                want_focus = true;
     5800            else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
     5801                want_focus = true;
     5802        }
     5803
     5804        // Handle manual resize: Resize Grips, Borders, Gamepad
     5805        int border_held = -1;
     5806        ImU32 resize_grip_col[4] = {};
     5807        const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
     5808        const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
     5809        if (!window->Collapsed)
     5810            if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
     5811                use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
     5812        window->ResizeBorderHeld = (signed char)border_held;
     5813
     5814        // SCROLLBAR VISIBILITY
     5815
     5816        // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).
     5817        if (!window->Collapsed)
     5818        {
     5819            // When reading the current size we need to read it after size constraints have been applied.
     5820            // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again.
     5821            ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height);
     5822            ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes;
     5823            ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
     5824            float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
     5825            float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
     5826            //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
     5827            window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
     5828            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));
     5829            if (window->ScrollbarX && !window->ScrollbarY)
     5830                window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
     5831            window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
     5832        }
     5833
     5834        // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)
     5835        // Update various regions. Variables they depends on should be set above in this function.
     5836        // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.
     5837
     5838        // Outer rectangle
     5839        // Not affected by window border size. Used by:
     5840        // - FindHoveredWindow() (w/ extra padding when border resize is enabled)
     5841        // - Begin() initial clipping rect for drawing window background and borders.
     5842        // - Begin() clipping whole child
     5843        const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
     5844        const ImRect outer_rect = window->Rect();
     5845        const ImRect title_bar_rect = window->TitleBarRect();
     5846        window->OuterRectClipped = outer_rect;
     5847        window->OuterRectClipped.ClipWith(host_rect);
     5848
     5849        // Inner rectangle
     5850        // Not affected by window border size. Used by:
     5851        // - InnerClipRect
     5852        // - ScrollToBringRectIntoView()
     5853        // - NavUpdatePageUpPageDown()
     5854        // - Scrollbar()
     5855        window->InnerRect.Min.x = window->Pos.x;
     5856        window->InnerRect.Min.y = window->Pos.y + decoration_up_height;
     5857        window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x;
     5858        window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y;
     5859
     5860        // Inner clipping rectangle.
     5861        // Will extend a little bit outside the normal work region.
     5862        // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
     5863        // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
     5864        // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
     5865        // Affected by window/frame border size. Used by:
     5866        // - Begin() initial clip rect
     5867        float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
     5868        window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
     5869        window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
     5870        window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
     5871        window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
     5872        window->InnerClipRect.ClipWithFull(host_rect);
     5873
     5874        // Default item width. Make it proportional to window size if window manually resizes
     5875        if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
     5876            window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f);
     5877        else
     5878            window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f);
     5879
     5880        // SCROLLING
     5881
     5882        // Lock down maximum scrolling
     5883        // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate
     5884        // for right/bottom aligned items without creating a scrollbar.
     5885        window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
     5886        window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
     5887
     5888        // Apply scrolling
     5889        window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);
     5890        window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
     5891
     5892        // DRAWING
     5893
     5894        // Setup draw list and outer clipping rectangle
     5895        IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0);
     5896        window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
     5897        PushClipRect(host_rect.Min, host_rect.Max, false);
     5898
     5899        // Draw modal window background (darkens what is behind them, all viewports)
     5900        const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
     5901        const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow);
     5902        if (dim_bg_for_modal || dim_bg_for_window_list)
     5903        {
     5904            const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
     5905            window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col);
     5906        }
     5907
     5908        // Draw navigation selection/windowing rectangle background
     5909        if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim)
     5910        {
     5911            ImRect bb = window->Rect();
     5912            bb.Expand(g.FontSize);
     5913            if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
     5914                window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
     5915        }
     5916
     5917        // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call.
     5918        // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
     5919        // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child.
     5920        // We also disabled this when we have dimming overlay behind this specific one child.
     5921        // 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.
     5922        {
     5923            bool render_decorations_in_parent = false;
     5924            if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
     5925                if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0)
     5926                    render_decorations_in_parent = true;
     5927            if (render_decorations_in_parent)
     5928                window->DrawList = parent_window->DrawList;
     5929
     5930            // Handle title bar, scrollbar, resize grips and resize borders
     5931            const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
     5932            const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
     5933            RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size);
     5934
     5935            if (render_decorations_in_parent)
     5936                window->DrawList = &window->DrawListInst;
     5937        }
     5938
     5939        // Draw navigation selection/windowing rectangle border
     5940        if (g.NavWindowingTargetAnim == window)
     5941        {
     5942            float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
     5943            ImRect bb = window->Rect();
     5944            bb.Expand(g.FontSize);
     5945            if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
     5946            {
     5947                bb.Expand(-g.FontSize - 1.0f);
     5948                rounding = window->WindowRounding;
     5949            }
     5950            window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
     5951        }
     5952
     5953        // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
     5954
     5955        // Work rectangle.
     5956        // Affected by window padding and border size. Used by:
     5957        // - Columns() for right-most edge
     5958        // - TreeNode(), CollapsingHeader() for right-most edge
     5959        // - BeginTabBar() for right-most edge
     5960        const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
     5961        const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
     5962        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));
     5963        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));
     5964        window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
     5965        window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
     5966        window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
     5967        window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
     5968        window->ParentWorkRect = window->WorkRect;
     5969
     5970        // [LEGACY] Content Region
     5971        // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
     5972        // Used by:
     5973        // - Mouse wheel scrolling + many other things
     5974        window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
     5975        window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
     5976        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));
     5977        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));
     5978
     5979        // Setup drawing context
     5980        // (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.)
     5981        window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
     5982        window->DC.GroupOffset.x = 0.0f;
     5983        window->DC.ColumnsOffset.x = 0.0f;
     5984        window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y);
     5985        window->DC.CursorPos = window->DC.CursorStartPos;
     5986        window->DC.CursorPosPrevLine = window->DC.CursorPos;
     5987        window->DC.CursorMaxPos = window->DC.CursorStartPos;
     5988        window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
     5989        window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
     5990
     5991        window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
     5992        window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
     5993        window->DC.NavLayerActiveMaskNext = 0x00;
     5994        window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // -V595
     5995        window->DC.NavHideHighlightOneFrame = false;
     5996        window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
     5997
     5998        window->DC.MenuBarAppending = false;
     5999        window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
     6000        window->DC.TreeDepth = 0;
     6001        window->DC.TreeJumpToParentOnPopMask = 0x00;
     6002        window->DC.ChildWindows.resize(0);
     6003        window->DC.StateStorage = &window->StateStorage;
     6004        window->DC.CurrentColumns = NULL;
     6005        window->DC.LayoutType = ImGuiLayoutType_Vertical;
     6006        window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
     6007        window->DC.FocusCounterRegular = window->DC.FocusCounterTabStop = -1;
     6008
     6009        window->DC.ItemWidth = window->ItemWidthDefault;
     6010        window->DC.TextWrapPos = -1.0f; // disabled
     6011        window->DC.ItemFlagsStack.resize(0);
     6012        window->DC.ItemWidthStack.resize(0);
     6013        window->DC.TextWrapPosStack.resize(0);
     6014        window->DC.GroupStack.resize(0);
     6015        window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_;
     6016        if (parent_window)
     6017            window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
     6018
     6019        if (window->AutoFitFramesX > 0)
     6020            window->AutoFitFramesX--;
     6021        if (window->AutoFitFramesY > 0)
     6022            window->AutoFitFramesY--;
     6023
     6024        // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
     6025        if (want_focus)
     6026        {
    58546027            FocusWindow(window);
    5855          }
    5856       }
    5857       else
    5858       {
    5859          window->Collapsed = false;
    5860       }
    5861       window->CollapseToggleWanted = false;
    5862 
    5863       // SIZE
    5864 
    5865       // Calculate auto-fit size, handle automatic resize
    5866       const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents);
    5867       ImVec2 size_full_modified(FLT_MAX, FLT_MAX);
    5868       if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
    5869       {
    5870          // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
    5871          if (!window_size_x_set_by_api)
    5872             window->SizeFull.x = size_full_modified.x = size_auto_fit.x;
    5873          if (!window_size_y_set_by_api)
    5874             window->SizeFull.y = size_full_modified.y = size_auto_fit.y;
    5875       }
    5876       else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
    5877       {
    5878          // Auto-fit may only grow window during the first few frames
    5879          // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
    5880          if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
    5881             window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
    5882          if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
    5883             window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
    5884          if (!window->Collapsed)
    5885             MarkIniSettingsDirty(window);
    5886       }
    5887 
    5888       // Apply minimum/maximum window size constraints and final size
    5889       window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull);
    5890       window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
    5891 
    5892       // SCROLLBAR STATUS
    5893 
    5894       // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size).
    5895       if (!window->Collapsed)
    5896       {
    5897          // When reading the current size we need to read it after size constraints have been applied
    5898          float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x;
    5899          float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y;
    5900          window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
    5901          window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
    5902          if (window->ScrollbarX && !window->ScrollbarY)
    5903             window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
    5904          window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
    5905       }
    5906 
    5907       // POSITION
    5908 
    5909       // Popup latch its initial position, will position itself when it appears next frame
    5910       if (window_just_activated_by_user)
    5911       {
    5912          window->AutoPosLastDirection = ImGuiDir_None;
    5913          if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
    5914             window->Pos = g.CurrentPopupStack.back().OpenPopupPos;
    5915       }
    5916 
    5917       // Position child window
    5918       if (flags & ImGuiWindowFlags_ChildWindow)
    5919       {
    5920          window->BeginOrderWithinParent = parent_window->DC.ChildWindows.Size;
    5921          parent_window->DC.ChildWindows.push_back(window);
    5922          if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
    5923             window->Pos = parent_window->DC.CursorPos;
    5924       }
    5925 
    5926       const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFrames == 0);
    5927       if (window_pos_with_pivot)
    5928          SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0); // Position given a pivot (e.g. for centering)
    5929       else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
    5930          window->Pos = FindBestWindowPosForPopup(window);
    5931       else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
    5932          window->Pos = FindBestWindowPosForPopup(window);
    5933       else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
    5934          window->Pos = FindBestWindowPosForPopup(window);
    5935 
    5936       // Clamp position so it stays visible
    5937       if (!(flags & ImGuiWindowFlags_ChildWindow))
    5938       {
    5939          if (!window_pos_set_by_api && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
    5940          {
    5941             ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
    5942             window->Pos = ImMax(window->Pos + window->Size, padding) - window->Size;
    5943             window->Pos = ImMin(window->Pos, g.IO.DisplaySize - padding);
    5944          }
    5945       }
    5946       window->Pos = ImFloor(window->Pos);
    5947 
    5948       // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
    5949       window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
    5950 
    5951       // Prepare for focus requests
    5952       window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter + 1)) % (window->FocusIdxAllCounter + 1);
    5953       window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter + 1)) % (window->FocusIdxTabCounter + 1);
    5954       window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1;
    5955       window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX;
    5956 
    5957       // Apply scrolling
    5958       window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);
    5959       window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
    5960 
    5961       // Apply focus, new windows appears in front
    5962       bool want_focus = false;
    5963       if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
    5964          if (!(flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
    5965             want_focus = true;
    5966 
    5967       // Handle manual resize: Resize Grips, Borders, Gamepad
    5968       int border_held = -1;
    5969       ImU32 resize_grip_col[4] = { 0 };
    5970       const int resize_grip_count = (flags & ImGuiWindowFlags_ResizeFromAnySide) ? 2 : 1; // 4
    5971       const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
    5972       if (!window->Collapsed)
    5973          UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]);
    5974 
    5975       // Default item width. Make it proportional to window size if window manually resizes
    5976       if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
    5977          window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
    5978       else
    5979          window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
    5980 
    5981       // DRAWING
    5982 
    5983       // Setup draw list and outer clipping rectangle
    5984       window->DrawList->Clear();
    5985       window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
    5986       window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
    5987       ImRect viewport_rect(GetViewportRect());
    5988       if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
    5989          PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true);
    5990       else
    5991          PushClipRect(viewport_rect.Min, viewport_rect.Max, true);
    5992 
    5993       // Draw modal window background (darkens what is behind them)
    5994       if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostPopupModal())
    5995          window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
    5996 
    5997       // Draw navigation selection/windowing rectangle background
    5998       if (g.NavWindowingTarget == window)
    5999       {
    6000          ImRect bb = window->Rect();
    6001          bb.Expand(g.FontSize);
    6002          if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
    6003             window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
    6004       }
    6005 
    6006       // Draw window + handle manual resize
    6007       const float window_rounding = window->WindowRounding;
    6008       const float window_border_size = window->WindowBorderSize;
    6009       const bool title_bar_is_highlight = want_focus || (g.NavWindow && window->RootWindowForTitleBarHighlight == g.NavWindow->RootWindowForTitleBarHighlight);
    6010       const ImRect title_bar_rect = window->TitleBarRect();
    6011       if (window->Collapsed)
    6012       {
    6013          // Title bar only
    6014          float backup_border_size = style.FrameBorderSize;
    6015          g.Style.FrameBorderSize = window->WindowBorderSize;
    6016          ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
    6017          RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
    6018          g.Style.FrameBorderSize = backup_border_size;
    6019       }
    6020       else
    6021       {
    6022          // Window background
    6023          ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
    6024          if (g.NextWindowData.BgAlphaCond != 0)
    6025          {
    6026             bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(g.NextWindowData.BgAlphaVal) << IM_COL32_A_SHIFT);
    6027             g.NextWindowData.BgAlphaCond = 0;
    6028          }
    6029          window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
    6030 
    6031          // Title bar
    6032          ImU32 title_bar_col = GetColorU32(window->Collapsed ? ImGuiCol_TitleBgCollapsed : title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
    6033          if (!(flags & ImGuiWindowFlags_NoTitleBar))
    6034             window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
    6035 
    6036          // Menu bar
    6037          if (flags & ImGuiWindowFlags_MenuBar)
    6038          {
    6039             ImRect menu_bar_rect = window->MenuBarRect();
    6040             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.
    6041             window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
    6042             if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
    6043                window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
    6044          }
    6045 
    6046          // Scrollbars
    6047          if (window->ScrollbarX)
    6048             Scrollbar(ImGuiLayoutType_Horizontal);
    6049          if (window->ScrollbarY)
    6050             Scrollbar(ImGuiLayoutType_Vertical);
    6051 
    6052          // Render resize grips (after their input handling so we don't have a frame of latency)
    6053          if (!(flags & ImGuiWindowFlags_NoResize))
    6054          {
    6055             for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
    6056             {
    6057                const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
    6058                const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPos);
    6059                window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size)));
    6060                window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size)));
    6061                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);
    6062                window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
    6063             }
    6064          }
    6065 
    6066          // Borders
    6067          if (window_border_size > 0.0f)
    6068             window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), window_rounding, ImDrawCornerFlags_All, window_border_size);
    6069          if (border_held != -1)
    6070          {
    6071             ImRect border = GetBorderRect(window, border_held, grip_draw_size, 0.0f);
    6072             window->DrawList->AddLine(border.Min, border.Max, GetColorU32(ImGuiCol_SeparatorActive), ImMax(1.0f, window_border_size));
    6073          }
    6074          if (style.FrameBorderSize > 0 && !(flags & ImGuiWindowFlags_NoTitleBar))
    6075             window->DrawList->AddLine(title_bar_rect.GetBL() + ImVec2(style.WindowBorderSize, -1), title_bar_rect.GetBR() + ImVec2(-style.WindowBorderSize, -1), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
    6076       }
    6077 
    6078       // Draw navigation selection/windowing rectangle border
    6079       if (g.NavWindowingTarget == window)
    6080       {
    6081          float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
    6082          ImRect bb = window->Rect();
    6083          bb.Expand(g.FontSize);
    6084          if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
    6085          {
    6086             bb.Expand(-g.FontSize - 1.0f);
    6087             rounding = window->WindowRounding;
    6088          }
    6089          window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
    6090       }
    6091 
    6092       // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars.
    6093       window->SizeFullAtLastBegin = window->SizeFull;
    6094 
    6095       // Update ContentsRegionMax. All the variable it depends on are set above in this function.
    6096       window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x;
    6097       window->ContentsRegionRect.Min.y = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight();
    6098       window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x));
    6099       window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y));
    6100 
    6101       // Setup drawing context
    6102       // (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.)
    6103       window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x;
    6104       window->DC.GroupOffsetX = 0.0f;
    6105       window->DC.ColumnsOffsetX = 0.0f;
    6106       window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
    6107       window->DC.CursorPos = window->DC.CursorStartPos;
    6108       window->DC.CursorPosPrevLine = window->DC.CursorPos;
    6109       window->DC.CursorMaxPos = window->DC.CursorStartPos;
    6110       window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f;
    6111       window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
    6112       window->DC.NavHideHighlightOneFrame = false;
    6113       window->DC.NavHasScroll = (GetScrollMaxY() > 0.0f);
    6114       window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
    6115       window->DC.NavLayerActiveMaskNext = 0x00;
    6116       window->DC.MenuBarAppending = false;
    6117       window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
    6118       window->DC.ChildWindows.resize(0);
    6119       window->DC.LayoutType = ImGuiLayoutType_Vertical;
    6120       window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
    6121       window->DC.ItemFlags = ImGuiItemFlags_Default_;
    6122       window->DC.ItemWidth = window->ItemWidthDefault;
    6123       window->DC.TextWrapPos = -1.0f; // disabled
    6124       window->DC.ItemFlagsStack.resize(0);
    6125       window->DC.ItemWidthStack.resize(0);
    6126       window->DC.TextWrapPosStack.resize(0);
    6127       window->DC.ColumnsSet = NULL;
    6128       window->DC.TreeDepth = 0;
    6129       window->DC.TreeDepthMayJumpToParentOnPop = 0x00;
    6130       window->DC.StateStorage = &window->StateStorage;
    6131       window->DC.GroupStack.resize(0);
    6132       window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
    6133 
    6134       if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags))
    6135       {
    6136          window->DC.ItemFlags = parent_window->DC.ItemFlags;
    6137          window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
    6138       }
    6139 
    6140       if (window->AutoFitFramesX > 0)
    6141          window->AutoFitFramesX--;
    6142       if (window->AutoFitFramesY > 0)
    6143          window->AutoFitFramesY--;
    6144 
    6145       // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
    6146       if (want_focus)
    6147       {
    6148          FocusWindow(window);
    6149          NavInitWindow(window, false);
    6150       }
    6151 
    6152       // Title bar
    6153       if (!(flags & ImGuiWindowFlags_NoTitleBar))
    6154       {
    6155          // Close & collapse button are on layer 1 (same as menus) and don't default focus
    6156          const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
    6157          window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
    6158          window->DC.NavLayerCurrent++;
    6159          window->DC.NavLayerCurrentMask <<= 1;
    6160 
    6161          // Collapse button
    6162          if (!(flags & ImGuiWindowFlags_NoCollapse))
    6163          {
    6164             ImGuiID id = window->GetID("#COLLAPSE");
    6165             ImRect bb(window->Pos + style.FramePadding + ImVec2(1, 1), window->Pos + style.FramePadding + ImVec2(g.FontSize, g.FontSize) - ImVec2(1, 1));
    6166             ItemAdd(bb, id);
    6167             if (ButtonBehavior(bb, id, NULL, NULL))
    6168                window->CollapseToggleWanted = true; // Defer collapsing to next frame as we are too far in the Begin() function
    6169             RenderNavHighlight(bb, id);
    6170             RenderArrow(window->Pos + style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
    6171          }
    6172 
    6173          // Close button
    6174          if (p_open != NULL)
    6175          {
    6176             const float pad = style.FramePadding.y;
    6177             const float rad = g.FontSize * 0.5f;
    6178             if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad + 1))
    6179                *p_open = false;
    6180          }
    6181 
    6182          window->DC.NavLayerCurrent--;
    6183          window->DC.NavLayerCurrentMask >>= 1;
    6184          window->DC.ItemFlags = item_flags_backup;
    6185 
    6186          // Title text (FIXME: refactor text alignment facilities along with RenderText helpers, this is too much code for what it does.)
    6187          ImVec2 text_size = CalcTextSize(name, NULL, true);
    6188          ImRect text_r = title_bar_rect;
    6189          float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
    6190          float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
    6191          if (style.WindowTitleAlign.x > 0.0f)
    6192             pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x);
    6193          text_r.Min.x += pad_left;
    6194          text_r.Max.x -= pad_right;
    6195          ImRect clip_rect = text_r;
    6196          clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton()
    6197          RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect);
    6198       }
    6199 
    6200       // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
    6201       window->WindowRectClipped = window->Rect();
    6202       window->WindowRectClipped.ClipWith(window->ClipRect);
    6203 
    6204       // Pressing CTRL+C while holding on a window copy its content to the clipboard
    6205       // 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.
    6206       // Maybe we can support CTRL+C on every element?
    6207       /*
    6208       if (g.ActiveId == move_id)
    6209       if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
    6210       ImGui::LogToClipboard();
    6211       */
    6212 
    6213       // Inner rectangle
    6214       // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
    6215       // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
    6216       window->InnerRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize;
    6217       window->InnerRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
    6218       window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - window->WindowBorderSize;
    6219       window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y - window->WindowBorderSize;
    6220       //window->DrawList->AddRect(window->InnerRect.Min, window->InnerRect.Max, IM_COL32_WHITE);
    6221 
    6222       // Inner clipping rectangle
    6223       // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
    6224       window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize)));
    6225       window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y);
    6226       window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize)));
    6227       window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y);
    6228 
    6229       // After Begin() we fill the last item / hovered data based on title bar data. It is a standard behavior (to allow creation of context menus on title bar only, etc.).
    6230       window->DC.LastItemId = window->MoveId;
    6231       window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
    6232       window->DC.LastItemRect = title_bar_rect;
    6233    }
    6234 
    6235    PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
    6236 
    6237    // 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)
    6238    if (first_begin_of_the_frame)
    6239       window->WriteAccessed = false;
    6240 
    6241    window->BeginCount++;
    6242    g.NextWindowData.Clear();
    6243 
    6244    // Child window can be out of sight and have "negative" clip windows.
    6245    // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
    6246    if (flags & ImGuiWindowFlags_ChildWindow)
    6247    {
    6248       IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
    6249       window->Collapsed = parent_window && parent_window->Collapsed;
    6250 
    6251       if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
    6252          window->Collapsed |= (window->WindowRectClipped.Min.x >= window->WindowRectClipped.Max.x || window->WindowRectClipped.Min.y >= window->WindowRectClipped.Max.y);
    6253 
    6254       // We also hide the window from rendering because we've already added its border to the command list.
    6255       // (we could perform the check earlier in the function but it is simpler at this point)
    6256       if (window->Collapsed)
    6257          window->Active = false;
    6258    }
    6259    if (style.Alpha <= 0.0f)
    6260       window->Active = false;
    6261 
    6262    // Return false if we don't intend to display anything to allow user to perform an early out optimization
    6263    window->SkipItems = (window->Collapsed || !window->Active) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0;
    6264    return !window->SkipItems;
    6265 }
    6266 
    6267 // Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead.
    6268 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    6269 bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags)
    6270 {
    6271    // Old API feature: we could pass the initial window size as a parameter. This was misleading because it only had an effect if the window didn't have data in the .ini file.
    6272    if (size_first_use.x != 0.0f || size_first_use.y != 0.0f)
    6273       ImGui::SetNextWindowSize(size_first_use, ImGuiCond_FirstUseEver);
    6274 
    6275    // Old API feature: override the window background alpha with a parameter.
    6276    if (bg_alpha_override >= 0.0f)
    6277       ImGui::SetNextWindowBgAlpha(bg_alpha_override);
    6278 
    6279    return ImGui::Begin(name, p_open, flags);
    6280 }
    6281 #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     6028            NavInitWindow(window, false);
     6029        }
     6030
     6031        // Title bar
     6032        if (!(flags & ImGuiWindowFlags_NoTitleBar))
     6033            RenderWindowTitleBarContents(window, title_bar_rect, name, p_open);
     6034
     6035        // Clear hit test shape every frame
     6036        window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;
     6037
     6038        // Pressing CTRL+C while holding on a window copy its content to the clipboard
     6039        // 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.
     6040        // Maybe we can support CTRL+C on every element?
     6041        /*
     6042        if (g.ActiveId == move_id)
     6043            if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
     6044                LogToClipboard();
     6045        */
     6046
     6047        // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
     6048        // This is useful to allow creating context menus on title bar only, etc.
     6049        SetLastItemData(window, window->MoveId, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
     6050
     6051#ifdef IMGUI_ENABLE_TEST_ENGINE
     6052        if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
     6053            IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId);
     6054#endif
     6055    }
     6056    else
     6057    {
     6058        // Append
     6059        SetCurrentWindow(window);
     6060    }
     6061
     6062    PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
     6063
     6064    // 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)
     6065    if (first_begin_of_the_frame)
     6066        window->WriteAccessed = false;
     6067
     6068    window->BeginCount++;
     6069    g.NextWindowData.ClearFlags();
     6070
     6071    // Update visibility
     6072    if (first_begin_of_the_frame)
     6073    {
     6074        if (flags & ImGuiWindowFlags_ChildWindow)
     6075        {
     6076            // Child window can be out of sight and have "negative" clip windows.
     6077            // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
     6078            IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
     6079            if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
     6080                if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
     6081                    window->HiddenFramesCanSkipItems = 1;
     6082
     6083            // Hide along with parent or if parent is collapsed
     6084            if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
     6085                window->HiddenFramesCanSkipItems = 1;
     6086            if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
     6087                window->HiddenFramesCannotSkipItems = 1;
     6088        }
     6089
     6090        // 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)
     6091        if (style.Alpha <= 0.0f)
     6092            window->HiddenFramesCanSkipItems = 1;
     6093
     6094        // Update the Hidden flag
     6095        window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
     6096
     6097        // Update the SkipItems flag, used to early out of all items functions (no layout required)
     6098        bool skip_items = false;
     6099        if (window->Collapsed || !window->Active || window->Hidden)
     6100            if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
     6101                skip_items = true;
     6102        window->SkipItems = skip_items;
     6103    }
     6104
     6105    return !window->SkipItems;
     6106}
    62826107
    62836108void ImGui::End()
    62846109{
    6285    ImGuiContext& g = *GImGui;
    6286    ImGuiWindow* window = g.CurrentWindow;
    6287 
    6288    if (window->DC.ColumnsSet != NULL)
    6289       EndColumns();
    6290    PopClipRect();   // Inner window clip rectangle
    6291 
    6292                     // Stop logging
    6293    if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging
    6294       LogFinish();
    6295 
    6296    // Pop from window stack
    6297    g.CurrentWindowStack.pop_back();
    6298    if (window->Flags & ImGuiWindowFlags_Popup)
    6299       g.CurrentPopupStack.pop_back();
    6300    CheckStacksSize(window, false);
    6301    SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
    6302 }
    6303 
    6304 // Vertical scrollbar
    6305 // The entire piece of code below is rather confusing because:
    6306 // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
    6307 // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
    6308 // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
    6309 void ImGui::Scrollbar(ImGuiLayoutType direction)
    6310 {
    6311    ImGuiContext& g = *GImGui;
    6312    ImGuiWindow* window = g.CurrentWindow;
    6313 
    6314    const bool horizontal = (direction == ImGuiLayoutType_Horizontal);
    6315    const ImGuiStyle& style = g.Style;
    6316    const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY");
    6317 
    6318    // Render background
    6319    bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
    6320    float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f;
    6321    const ImRect window_rect = window->Rect();
    6322    const float border_size = window->WindowBorderSize;
    6323    ImRect bb = horizontal
    6324       ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size)
    6325       : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size);
    6326    if (!horizontal)
    6327       bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f);
    6328    if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f)
    6329       return;
    6330 
    6331    int window_rounding_corners;
    6332    if (horizontal)
    6333       window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
    6334    else
    6335       window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
    6336    window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners);
    6337    bb.Expand(ImVec2(-ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f)));
    6338 
    6339    // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar)
    6340    float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
    6341    float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y;
    6342    float win_size_avail_v = (horizontal ? window->SizeFull.x : window->SizeFull.y) - other_scrollbar_size_w;
    6343    float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y;
    6344 
    6345    // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount)
    6346    // But we maintain a minimum size in pixel to allow for the user to still aim inside.
    6347    IM_ASSERT(ImMax(win_size_contents_v, win_size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
    6348    const float win_size_v = ImMax(ImMax(win_size_contents_v, win_size_avail_v), 1.0f);
    6349    const float grab_h_pixels = ImClamp(scrollbar_size_v * (win_size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v);
    6350    const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
    6351 
    6352    // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
    6353    bool held = false;
    6354    bool hovered = false;
    6355    const bool previously_held = (g.ActiveId == id);
    6356    ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);
    6357 
    6358    float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v);
    6359    float scroll_ratio = ImSaturate(scroll_v / scroll_max);
    6360    float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
    6361    if (held && grab_h_norm < 1.0f)
    6362    {
    6363       float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y;
    6364       float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
    6365       float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y;
    6366 
    6367       // Click position in scrollbar normalized space (0.0f->1.0f)
    6368       const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);
    6369       SetHoveredID(id);
    6370 
    6371       bool seek_absolute = false;
    6372       if (!previously_held)
    6373       {
    6374          // On initial click calculate the distance between mouse and the center of the grab
    6375          if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm)
    6376          {
    6377             *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f;
    6378          }
    6379          else
    6380          {
    6381             seek_absolute = true;
    6382             *click_delta_to_grab_center_v = 0.0f;
    6383          }
    6384       }
    6385 
    6386       // Apply scroll
    6387       // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position
    6388       const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm * 0.5f) / (1.0f - grab_h_norm));
    6389       scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
    6390       if (horizontal)
    6391          window->Scroll.x = scroll_v;
    6392       else
    6393          window->Scroll.y = scroll_v;
    6394 
    6395       // Update values for rendering
    6396       scroll_ratio = ImSaturate(scroll_v / scroll_max);
    6397       grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
    6398 
    6399       // Update distance to grab now that we have seeked and saturated
    6400       if (seek_absolute)
    6401          *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f;
    6402    }
    6403 
    6404    // Render
    6405    const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab);
    6406    ImRect grab_rect;
    6407    if (horizontal)
    6408       grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, window_rect.Max.x), bb.Max.y);
    6409    else
    6410       grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, window_rect.Max.y));
    6411    window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding);
    6412 }
    6413 
    6414 void ImGui::BringWindowToFront(ImGuiWindow* window)
    6415 {
    6416    ImGuiContext& g = *GImGui;
    6417    ImGuiWindow* current_front_window = g.Windows.back();
    6418    if (current_front_window == window || current_front_window->RootWindow == window)
    6419       return;
    6420    for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window
    6421       if (g.Windows[i] == window)
    6422       {
    6423          g.Windows.erase(g.Windows.Data + i);
    6424          g.Windows.push_back(window);
    6425          break;
    6426       }
    6427 }
    6428 
    6429 void ImGui::BringWindowToBack(ImGuiWindow* window)
    6430 {
    6431    ImGuiContext& g = *GImGui;
    6432    if (g.Windows[0] == window)
    6433       return;
    6434    for (int i = 0; i < g.Windows.Size; i++)
    6435       if (g.Windows[i] == window)
    6436       {
    6437          memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
    6438          g.Windows[0] = window;
    6439          break;
    6440       }
     6110    ImGuiContext& g = *GImGui;
     6111    ImGuiWindow* window = g.CurrentWindow;
     6112
     6113    // Error checking: verify that user hasn't called End() too many times!
     6114    if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow)
     6115    {
     6116        IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
     6117        return;
     6118    }
     6119    IM_ASSERT(g.CurrentWindowStack.Size > 0);
     6120
     6121    // Error checking: verify that user doesn't directly call End() on a child window.
     6122    if (window->Flags & ImGuiWindowFlags_ChildWindow)
     6123        IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!");
     6124
     6125    // Close anything that is open
     6126    if (window->DC.CurrentColumns)
     6127        EndColumns();
     6128    PopClipRect();   // Inner window clip rectangle
     6129
     6130    // Stop logging
     6131    if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging
     6132        LogFinish();
     6133
     6134    // Pop from window stack
     6135    g.CurrentWindowStack.pop_back();
     6136    if (window->Flags & ImGuiWindowFlags_Popup)
     6137        g.BeginPopupStack.pop_back();
     6138    ErrorCheckBeginEndCompareStacksSize(window, false);
     6139    SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
     6140}
     6141
     6142void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
     6143{
     6144    ImGuiContext& g = *GImGui;
     6145    if (g.WindowsFocusOrder.back() == window)
     6146        return;
     6147    for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window
     6148        if (g.WindowsFocusOrder[i] == window)
     6149        {
     6150            memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
     6151            g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window;
     6152            break;
     6153        }
     6154}
     6155
     6156void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
     6157{
     6158    ImGuiContext& g = *GImGui;
     6159    ImGuiWindow* current_front_window = g.Windows.back();
     6160    if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better)
     6161        return;
     6162    for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
     6163        if (g.Windows[i] == window)
     6164        {
     6165            memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
     6166            g.Windows[g.Windows.Size - 1] = window;
     6167            break;
     6168        }
     6169}
     6170
     6171void ImGui::BringWindowToDisplayBack(ImGuiWindow* window)
     6172{
     6173    ImGuiContext& g = *GImGui;
     6174    if (g.Windows[0] == window)
     6175        return;
     6176    for (int i = 0; i < g.Windows.Size; i++)
     6177        if (g.Windows[i] == window)
     6178        {
     6179            memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
     6180            g.Windows[0] = window;
     6181            break;
     6182        }
    64416183}
    64426184
     
    64446186void ImGui::FocusWindow(ImGuiWindow* window)
    64456187{
    6446    ImGuiContext& g = *GImGui;
    6447 
    6448    if (g.NavWindow != window)
    6449    {
    6450       g.NavWindow = window;
    6451       if (window && g.NavDisableMouseHover)
    6452          g.NavMousePosDirty = true;
    6453       g.NavInitRequest = false;
    6454       g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
    6455       g.NavIdIsAlive = false;
    6456       g.NavLayer = 0;
    6457       //printf("[%05d] FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL);
    6458    }
    6459 
    6460    // Passing NULL allow to disable keyboard focus
    6461    if (!window)
    6462       return;
    6463 
    6464    // Move the root window to the top of the pile
    6465    if (window->RootWindow)
    6466       window = window->RootWindow;
    6467 
    6468    // Steal focus on active widgets
    6469    if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it..
    6470       if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window)
    6471          ClearActiveID();
    6472 
    6473    // Bring to front
    6474    if (!(window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus))
    6475       BringWindowToFront(window);
    6476 }
    6477 
    6478 void ImGui::FocusFrontMostActiveWindow(ImGuiWindow* ignore_window)
    6479 {
    6480    ImGuiContext& g = *GImGui;
    6481    for (int i = g.Windows.Size - 1; i >= 0; i--)
    6482       if (g.Windows[i] != ignore_window && g.Windows[i]->WasActive && !(g.Windows[i]->Flags & ImGuiWindowFlags_ChildWindow))
    6483       {
    6484          ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(g.Windows[i]);
    6485          FocusWindow(focus_window);
    6486          return;
    6487       }
    6488 }
    6489 
    6490 void ImGui::PushItemWidth(float item_width)
    6491 {
    6492    ImGuiWindow* window = GetCurrentWindow();
    6493    window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
    6494    window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
    6495 }
    6496 
    6497 void ImGui::PushMultiItemsWidths(int components, float w_full)
    6498 {
    6499    ImGuiWindow* window = GetCurrentWindow();
    6500    const ImGuiStyle& style = GImGui->Style;
    6501    if (w_full <= 0.0f)
    6502       w_full = CalcItemWidth();
    6503    const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));
    6504    const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));
    6505    window->DC.ItemWidthStack.push_back(w_item_last);
    6506    for (int i = 0; i < components - 1; i++)
    6507       window->DC.ItemWidthStack.push_back(w_item_one);
    6508    window->DC.ItemWidth = window->DC.ItemWidthStack.back();
    6509 }
    6510 
    6511 void ImGui::PopItemWidth()
    6512 {
    6513    ImGuiWindow* window = GetCurrentWindow();
    6514    window->DC.ItemWidthStack.pop_back();
    6515    window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
    6516 }
    6517 
    6518 float ImGui::CalcItemWidth()
    6519 {
    6520    ImGuiWindow* window = GetCurrentWindowRead();
    6521    float w = window->DC.ItemWidth;
    6522    if (w < 0.0f)
    6523    {
    6524       // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well.
    6525       float width_to_right_edge = GetContentRegionAvail().x;
    6526       w = ImMax(1.0f, width_to_right_edge + w);
    6527    }
    6528    w = (float)(int)w;
    6529    return w;
    6530 }
    6531 
    6532 static ImFont* GetDefaultFont()
    6533 {
    6534    ImGuiContext& g = *GImGui;
    6535    return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0];
     6188    ImGuiContext& g = *GImGui;
     6189
     6190    if (g.NavWindow != window)
     6191    {
     6192        g.NavWindow = window;
     6193        if (window && g.NavDisableMouseHover)
     6194            g.NavMousePosDirty = true;
     6195        g.NavInitRequest = false;
     6196        g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
     6197        g.NavFocusScopeId = 0;
     6198        g.NavIdIsAlive = false;
     6199        g.NavLayer = ImGuiNavLayer_Main;
     6200        //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
     6201    }
     6202
     6203    // Close popups if any
     6204    ClosePopupsOverWindow(window, false);
     6205
     6206    // Move the root window to the top of the pile
     6207    IM_ASSERT(window == NULL || window->RootWindow != NULL);
     6208    ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop
     6209    ImGuiWindow* display_front_window = window ? window->RootWindow : NULL;
     6210
     6211    // Steal active widgets. Some of the cases it triggers includes:
     6212    // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run.
     6213    // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId)
     6214    if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)
     6215        if (!g.ActiveIdNoClearOnFocusLoss)
     6216            ClearActiveID();
     6217
     6218    // Passing NULL allow to disable keyboard focus
     6219    if (!window)
     6220        return;
     6221
     6222    // Bring to front
     6223    BringWindowToFocusFront(focus_front_window);
     6224    if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
     6225        BringWindowToDisplayFront(display_front_window);
     6226}
     6227
     6228void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window)
     6229{
     6230    ImGuiContext& g = *GImGui;
     6231
     6232    int start_idx = g.WindowsFocusOrder.Size - 1;
     6233    if (under_this_window != NULL)
     6234    {
     6235        int under_this_window_idx = FindWindowFocusIndex(under_this_window);
     6236        if (under_this_window_idx != -1)
     6237            start_idx = under_this_window_idx - 1;
     6238    }
     6239    for (int i = start_idx; i >= 0; i--)
     6240    {
     6241        // 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.
     6242        ImGuiWindow* window = g.WindowsFocusOrder[i];
     6243        if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow))
     6244            if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
     6245            {
     6246                ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
     6247                FocusWindow(focus_window);
     6248                return;
     6249            }
     6250    }
     6251    FocusWindow(NULL);
    65366252}
    65376253
    65386254void ImGui::SetCurrentFont(ImFont* font)
    65396255{
    6540    ImGuiContext& g = *GImGui;
    6541    IM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
    6542    IM_ASSERT(font->Scale > 0.0f);
    6543    g.Font = font;
    6544    g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale;
    6545    g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
    6546 
    6547    ImFontAtlas* atlas = g.Font->ContainerAtlas;
    6548    g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
    6549    g.DrawListSharedData.Font = g.Font;
    6550    g.DrawListSharedData.FontSize = g.FontSize;
     6256    ImGuiContext& g = *GImGui;
     6257    IM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
     6258    IM_ASSERT(font->Scale > 0.0f);
     6259    g.Font = font;
     6260    g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
     6261    g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
     6262
     6263    ImFontAtlas* atlas = g.Font->ContainerAtlas;
     6264    g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
     6265    g.DrawListSharedData.TexUvLines = atlas->TexUvLines;
     6266    g.DrawListSharedData.Font = g.Font;
     6267    g.DrawListSharedData.FontSize = g.FontSize;
    65516268}
    65526269
    65536270void ImGui::PushFont(ImFont* font)
    65546271{
    6555    ImGuiContext& g = *GImGui;
    6556    if (!font)
    6557       font = GetDefaultFont();
    6558    SetCurrentFont(font);
    6559    g.FontStack.push_back(font);
    6560    g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
     6272    ImGuiContext& g = *GImGui;
     6273    if (!font)
     6274        font = GetDefaultFont();
     6275    SetCurrentFont(font);
     6276    g.FontStack.push_back(font);
     6277    g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
    65616278}
    65626279
    65636280void  ImGui::PopFont()
    65646281{
    6565    ImGuiContext& g = *GImGui;
    6566    g.CurrentWindow->DrawList->PopTextureID();
    6567    g.FontStack.pop_back();
    6568    SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
     6282    ImGuiContext& g = *GImGui;
     6283    g.CurrentWindow->DrawList->PopTextureID();
     6284    g.FontStack.pop_back();
     6285    SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
    65696286}
    65706287
    65716288void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
    65726289{
    6573    ImGuiWindow* window = GetCurrentWindow();
    6574    if (enabled)
    6575       window->DC.ItemFlags |= option;
    6576    else
    6577       window->DC.ItemFlags &= ~option;
    6578    window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
     6290    ImGuiWindow* window = GetCurrentWindow();
     6291    if (enabled)
     6292        window->DC.ItemFlags |= option;
     6293    else
     6294        window->DC.ItemFlags &= ~option;
     6295    window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
    65796296}
    65806297
    65816298void ImGui::PopItemFlag()
    65826299{
    6583    ImGuiWindow* window = GetCurrentWindow();
    6584    window->DC.ItemFlagsStack.pop_back();
    6585    window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back();
    6586 }
    6587 
     6300    ImGuiWindow* window = GetCurrentWindow();
     6301    window->DC.ItemFlagsStack.pop_back();
     6302    window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back();
     6303}
     6304
     6305// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system.
    65886306void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
    65896307{
    6590    PushItemFlag(ImGuiItemFlags_AllowKeyboardFocus, allow_keyboard_focus);
     6308    PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus);
    65916309}
    65926310
    65936311void ImGui::PopAllowKeyboardFocus()
    65946312{
    6595    PopItemFlag();
     6313    PopItemFlag();
    65966314}
    65976315
    65986316void ImGui::PushButtonRepeat(bool repeat)
    65996317{
    6600    PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);
     6318    PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);
    66016319}
    66026320
    66036321void ImGui::PopButtonRepeat()
    66046322{
    6605    PopItemFlag();
     6323    PopItemFlag();
    66066324}
    66076325
    66086326void ImGui::PushTextWrapPos(float wrap_pos_x)
    66096327{
    6610    ImGuiWindow* window = GetCurrentWindow();
    6611    window->DC.TextWrapPos = wrap_pos_x;
    6612    window->DC.TextWrapPosStack.push_back(wrap_pos_x);
     6328    ImGuiWindow* window = GetCurrentWindow();
     6329    window->DC.TextWrapPos = wrap_pos_x;
     6330    window->DC.TextWrapPosStack.push_back(wrap_pos_x);
    66136331}
    66146332
    66156333void ImGui::PopTextWrapPos()
    66166334{
    6617    ImGuiWindow* window = GetCurrentWindow();
    6618    window->DC.TextWrapPosStack.pop_back();
    6619    window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
    6620 }
    6621 
    6622 // 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
    6623 void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)
    6624 {
    6625    ImGuiContext& g = *GImGui;
    6626    ImGuiColMod backup;
    6627    backup.Col = idx;
    6628    backup.BackupValue = g.Style.Colors[idx];
    6629    g.ColorModifiers.push_back(backup);
    6630    g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
    6631 }
    6632 
    6633 void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
    6634 {
    6635    ImGuiContext& g = *GImGui;
    6636    ImGuiColMod backup;
    6637    backup.Col = idx;
    6638    backup.BackupValue = g.Style.Colors[idx];
    6639    g.ColorModifiers.push_back(backup);
    6640    g.Style.Colors[idx] = col;
    6641 }
    6642 
    6643 void ImGui::PopStyleColor(int count)
    6644 {
    6645    ImGuiContext& g = *GImGui;
    6646    while (count > 0)
    6647    {
    6648       ImGuiColMod& backup = g.ColorModifiers.back();
    6649       g.Style.Colors[backup.Col] = backup.BackupValue;
    6650       g.ColorModifiers.pop_back();
    6651       count--;
    6652    }
    6653 }
    6654 
    6655 struct ImGuiStyleVarInfo
    6656 {
    6657    ImGuiDataType   Type;
    6658    ImU32           Count;
    6659    ImU32           Offset;
    6660    void*           GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
    6661 };
    6662 
    6663 static const ImGuiStyleVarInfo GStyleVarInfo[] =
    6664 {
    6665    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) },              // ImGuiStyleVar_Alpha
    6666 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) },      // ImGuiStyleVar_WindowPadding
    6667 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) },     // ImGuiStyleVar_WindowRounding
    6668 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) },   // ImGuiStyleVar_WindowBorderSize
    6669 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) },      // ImGuiStyleVar_WindowMinSize
    6670 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) },   // ImGuiStyleVar_WindowTitleAlign
    6671 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) },      // ImGuiStyleVar_ChildRounding
    6672 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) },    // ImGuiStyleVar_ChildBorderSize
    6673 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) },      // ImGuiStyleVar_PopupRounding
    6674 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) },    // ImGuiStyleVar_PopupBorderSize
    6675 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) },       // ImGuiStyleVar_FramePadding
    6676 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) },      // ImGuiStyleVar_FrameRounding
    6677 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) },    // ImGuiStyleVar_FrameBorderSize
    6678 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) },        // ImGuiStyleVar_ItemSpacing
    6679 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) },   // ImGuiStyleVar_ItemInnerSpacing
    6680 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },      // ImGuiStyleVar_IndentSpacing
    6681 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) },      // ImGuiStyleVar_ScrollbarSize
    6682 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) },  // ImGuiStyleVar_ScrollbarRounding
    6683 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },        // ImGuiStyleVar_GrabMinSize
    6684 { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) },       // ImGuiStyleVar_GrabRounding
    6685 { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },    // ImGuiStyleVar_ButtonTextAlign
    6686 };
    6687 
    6688 static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
    6689 {
    6690    IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
    6691    IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
    6692    return &GStyleVarInfo[idx];
    6693 }
    6694 
    6695 void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
    6696 {
    6697    const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
    6698    if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
    6699    {
    6700       ImGuiContext& g = *GImGui;
    6701       float* pvar = (float*)var_info->GetVarPtr(&g.Style);
    6702       g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
    6703       *pvar = val;
    6704       return;
    6705    }
    6706    IM_ASSERT(0); // Called function with wrong-type? Variable is not a float.
    6707 }
    6708 
    6709 void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
    6710 {
    6711    const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
    6712    if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
    6713    {
    6714       ImGuiContext& g = *GImGui;
    6715       ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
    6716       g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
    6717       *pvar = val;
    6718       return;
    6719    }
    6720    IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2.
    6721 }
    6722 
    6723 void ImGui::PopStyleVar(int count)
    6724 {
    6725    ImGuiContext& g = *GImGui;
    6726    while (count > 0)
    6727    {
    6728       // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
    6729       ImGuiStyleMod& backup = g.StyleModifiers.back();
    6730       const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
    6731       void* data = info->GetVarPtr(&g.Style);
    6732       if (info->Type == ImGuiDataType_Float && info->Count == 1) { ((float*)data)[0] = backup.BackupFloat[0]; }
    6733       else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
    6734       g.StyleModifiers.pop_back();
    6735       count--;
    6736    }
    6737 }
    6738 
    6739 const char* ImGui::GetStyleColorName(ImGuiCol idx)
    6740 {
    6741    // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
    6742    switch (idx)
    6743    {
    6744    case ImGuiCol_Text: return "Text";
    6745    case ImGuiCol_TextDisabled: return "TextDisabled";
    6746    case ImGuiCol_WindowBg: return "WindowBg";
    6747    case ImGuiCol_ChildBg: return "ChildBg";
    6748    case ImGuiCol_PopupBg: return "PopupBg";
    6749    case ImGuiCol_Border: return "Border";
    6750    case ImGuiCol_BorderShadow: return "BorderShadow";
    6751    case ImGuiCol_FrameBg: return "FrameBg";
    6752    case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
    6753    case ImGuiCol_FrameBgActive: return "FrameBgActive";
    6754    case ImGuiCol_TitleBg: return "TitleBg";
    6755    case ImGuiCol_TitleBgActive: return "TitleBgActive";
    6756    case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
    6757    case ImGuiCol_MenuBarBg: return "MenuBarBg";
    6758    case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
    6759    case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
    6760    case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
    6761    case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
    6762    case ImGuiCol_CheckMark: return "CheckMark";
    6763    case ImGuiCol_SliderGrab: return "SliderGrab";
    6764    case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
    6765    case ImGuiCol_Button: return "Button";
    6766    case ImGuiCol_ButtonHovered: return "ButtonHovered";
    6767    case ImGuiCol_ButtonActive: return "ButtonActive";
    6768    case ImGuiCol_Header: return "Header";
    6769    case ImGuiCol_HeaderHovered: return "HeaderHovered";
    6770    case ImGuiCol_HeaderActive: return "HeaderActive";
    6771    case ImGuiCol_Separator: return "Separator";
    6772    case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
    6773    case ImGuiCol_SeparatorActive: return "SeparatorActive";
    6774    case ImGuiCol_ResizeGrip: return "ResizeGrip";
    6775    case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
    6776    case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
    6777    case ImGuiCol_PlotLines: return "PlotLines";
    6778    case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
    6779    case ImGuiCol_PlotHistogram: return "PlotHistogram";
    6780    case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
    6781    case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
    6782    case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening";
    6783    case ImGuiCol_DragDropTarget: return "DragDropTarget";
    6784    case ImGuiCol_NavHighlight: return "NavHighlight";
    6785    case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
    6786    }
    6787    IM_ASSERT(0);
    6788    return "Unknown";
     6335    ImGuiWindow* window = GetCurrentWindow();
     6336    window->DC.TextWrapPosStack.pop_back();
     6337    window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
    67896338}
    67906339
    67916340bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
    67926341{
    6793    if (window->RootWindow == potential_parent)
    6794       return true;
    6795    while (window != NULL)
    6796    {
    6797       if (window == potential_parent)
    6798          return true;
    6799       window = window->ParentWindow;
    6800    }
    6801    return false;
     6342    if (window->RootWindow == potential_parent)
     6343        return true;
     6344    while (window != NULL)
     6345    {
     6346        if (window == potential_parent)
     6347            return true;
     6348        window = window->ParentWindow;
     6349    }
     6350    return false;
    68026351}
    68036352
    68046353bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)
    68056354{
    6806    IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0);   // Flags not supported by this function
    6807    ImGuiContext& g = *GImGui;
    6808 
    6809    if (flags & ImGuiHoveredFlags_AnyWindow)
    6810    {
    6811       if (g.HoveredWindow == NULL)
    6812          return false;
    6813    }
    6814    else
    6815    {
    6816       switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows))
    6817       {
    6818       case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows:
    6819          if (g.HoveredRootWindow != g.CurrentWindow->RootWindow)
     6355    IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0);   // Flags not supported by this function
     6356    ImGuiContext& g = *GImGui;
     6357
     6358    if (flags & ImGuiHoveredFlags_AnyWindow)
     6359    {
     6360        if (g.HoveredWindow == NULL)
    68206361            return false;
    6821          break;
    6822       case ImGuiHoveredFlags_RootWindow:
    6823          if (g.HoveredWindow != g.CurrentWindow->RootWindow)
     6362    }
     6363    else
     6364    {
     6365        switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows))
     6366        {
     6367        case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows:
     6368            if (g.HoveredRootWindow != g.CurrentWindow->RootWindow)
     6369                return false;
     6370            break;
     6371        case ImGuiHoveredFlags_RootWindow:
     6372            if (g.HoveredWindow != g.CurrentWindow->RootWindow)
     6373                return false;
     6374            break;
     6375        case ImGuiHoveredFlags_ChildWindows:
     6376            if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow))
     6377                return false;
     6378            break;
     6379        default:
     6380            if (g.HoveredWindow != g.CurrentWindow)
     6381                return false;
     6382            break;
     6383        }
     6384    }
     6385
     6386    if (!IsWindowContentHoverable(g.HoveredWindow, flags))
     6387        return false;
     6388    if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
     6389        if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
    68246390            return false;
    6825          break;
    6826       case ImGuiHoveredFlags_ChildWindows:
    6827          if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow))
    6828             return false;
    6829          break;
    6830       default:
    6831          if (g.HoveredWindow != g.CurrentWindow)
    6832             return false;
    6833          break;
    6834       }
    6835    }
    6836 
    6837    if (!IsWindowContentHoverable(g.HoveredRootWindow, flags))
    6838       return false;
    6839    if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
    6840       if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
    6841          return false;
    6842    return true;
     6391    return true;
    68436392}
    68446393
    68456394bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
    68466395{
    6847    ImGuiContext& g = *GImGui;
    6848    IM_ASSERT(g.CurrentWindow);     // Not inside a Begin()/End()
    6849 
    6850    if (flags & ImGuiFocusedFlags_AnyWindow)
    6851       return g.NavWindow != NULL;
    6852 
    6853    switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))
    6854    {
    6855    case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:
    6856       return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
    6857    case ImGuiFocusedFlags_RootWindow:
    6858       return g.NavWindow == g.CurrentWindow->RootWindow;
    6859    case ImGuiFocusedFlags_ChildWindows:
    6860       return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
    6861    default:
    6862       return g.NavWindow == g.CurrentWindow;
    6863    }
     6396    ImGuiContext& g = *GImGui;
     6397
     6398    if (flags & ImGuiFocusedFlags_AnyWindow)
     6399        return g.NavWindow != NULL;
     6400
     6401    IM_ASSERT(g.CurrentWindow);     // Not inside a Begin()/End()
     6402    switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))
     6403    {
     6404    case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:
     6405        return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
     6406    case ImGuiFocusedFlags_RootWindow:
     6407        return g.NavWindow == g.CurrentWindow->RootWindow;
     6408    case ImGuiFocusedFlags_ChildWindows:
     6409        return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
     6410    default:
     6411        return g.NavWindow == g.CurrentWindow;
     6412    }
    68646413}
    68656414
    68666415// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
     6416// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically.
     6417// If you want a window to never be focused, you may use the e.g. NoInputs flag.
    68676418bool ImGui::IsWindowNavFocusable(ImGuiWindow* window)
    68686419{
    6869    ImGuiContext& g = *GImGui;
    6870    return window->Active && window == window->RootWindowForTabbing && (!(window->Flags & ImGuiWindowFlags_NoNavFocus) || window == g.NavWindow);
     6420    return window->Active && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);
    68716421}
    68726422
    68736423float ImGui::GetWindowWidth()
    68746424{
    6875    ImGuiWindow* window = GImGui->CurrentWindow;
    6876    return window->Size.x;
     6425    ImGuiWindow* window = GImGui->CurrentWindow;
     6426    return window->Size.x;
    68776427}
    68786428
    68796429float ImGui::GetWindowHeight()
    68806430{
    6881    ImGuiWindow* window = GImGui->CurrentWindow;
    6882    return window->Size.y;
     6431    ImGuiWindow* window = GImGui->CurrentWindow;
     6432    return window->Size.y;
    68836433}
    68846434
    68856435ImVec2 ImGui::GetWindowPos()
    68866436{
    6887    ImGuiContext& g = *GImGui;
    6888    ImGuiWindow* window = g.CurrentWindow;
    6889    return window->Pos;
    6890 }
    6891 
    6892 static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
    6893 {
    6894    window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
    6895    window->Scroll.x = new_scroll_x;
    6896    window->DC.CursorMaxPos.x -= window->Scroll.x;
    6897 }
    6898 
    6899 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
    6900 {
    6901    window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
    6902    window->Scroll.y = new_scroll_y;
    6903    window->DC.CursorMaxPos.y -= window->Scroll.y;
    6904 }
    6905 
    6906 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
    6907 {
    6908    // Test condition (NB: bit 0 is always true) and clear flags for next time
    6909    if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
    6910       return;
    6911 
    6912    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
    6913    window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
    6914    window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
    6915 
    6916    // Set
    6917    const ImVec2 old_pos = window->Pos;
    6918    window->Pos = ImFloor(pos);
    6919    window->DC.CursorPos += (window->Pos - old_pos);    // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
    6920    window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected.
     6437    ImGuiContext& g = *GImGui;
     6438    ImGuiWindow* window = g.CurrentWindow;
     6439    return window->Pos;
     6440}
     6441
     6442void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
     6443{
     6444    // Test condition (NB: bit 0 is always true) and clear flags for next time
     6445    if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
     6446        return;
     6447
     6448    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
     6449    window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
     6450    window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
     6451
     6452    // Set
     6453    const ImVec2 old_pos = window->Pos;
     6454    window->Pos = ImFloor(pos);
     6455    ImVec2 offset = window->Pos - old_pos;
     6456    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
     6457    window->DC.CursorMaxPos += offset;      // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
     6458    window->DC.CursorStartPos += offset;
    69216459}
    69226460
    69236461void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
    69246462{
    6925    ImGuiWindow* window = GetCurrentWindowRead();
    6926    SetWindowPos(window, pos, cond);
     6463    ImGuiWindow* window = GetCurrentWindowRead();
     6464    SetWindowPos(window, pos, cond);
    69276465}
    69286466
    69296467void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
    69306468{
    6931    if (ImGuiWindow* window = FindWindowByName(name))
    6932       SetWindowPos(window, pos, cond);
     6469    if (ImGuiWindow* window = FindWindowByName(name))
     6470        SetWindowPos(window, pos, cond);
    69336471}
    69346472
    69356473ImVec2 ImGui::GetWindowSize()
    69366474{
    6937    ImGuiWindow* window = GetCurrentWindowRead();
    6938    return window->Size;
    6939 }
    6940 
    6941 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
    6942 {
    6943    // Test condition (NB: bit 0 is always true) and clear flags for next time
    6944    if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
    6945       return;
    6946 
    6947    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
    6948    window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
    6949 
    6950    // Set
    6951    if (size.x > 0.0f)
    6952    {
    6953       window->AutoFitFramesX = 0;
    6954       window->SizeFull.x = size.x;
    6955    }
    6956    else
    6957    {
    6958       window->AutoFitFramesX = 2;
    6959       window->AutoFitOnlyGrows = false;
    6960    }
    6961    if (size.y > 0.0f)
    6962    {
    6963       window->AutoFitFramesY = 0;
    6964       window->SizeFull.y = size.y;
    6965    }
    6966    else
    6967    {
    6968       window->AutoFitFramesY = 2;
    6969       window->AutoFitOnlyGrows = false;
    6970    }
     6475    ImGuiWindow* window = GetCurrentWindowRead();
     6476    return window->Size;
     6477}
     6478
     6479void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
     6480{
     6481    // Test condition (NB: bit 0 is always true) and clear flags for next time
     6482    if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
     6483        return;
     6484
     6485    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
     6486    window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
     6487
     6488    // Set
     6489    if (size.x > 0.0f)
     6490    {
     6491        window->AutoFitFramesX = 0;
     6492        window->SizeFull.x = IM_FLOOR(size.x);
     6493    }
     6494    else
     6495    {
     6496        window->AutoFitFramesX = 2;
     6497        window->AutoFitOnlyGrows = false;
     6498    }
     6499    if (size.y > 0.0f)
     6500    {
     6501        window->AutoFitFramesY = 0;
     6502        window->SizeFull.y = IM_FLOOR(size.y);
     6503    }
     6504    else
     6505    {
     6506        window->AutoFitFramesY = 2;
     6507        window->AutoFitOnlyGrows = false;
     6508    }
    69716509}
    69726510
    69736511void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
    69746512{
    6975    SetWindowSize(GImGui->CurrentWindow, size, cond);
     6513    SetWindowSize(GImGui->CurrentWindow, size, cond);
    69766514}
    69776515
    69786516void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
    69796517{
    6980    if (ImGuiWindow* window = FindWindowByName(name))
    6981       SetWindowSize(window, size, cond);
    6982 }
    6983 
    6984 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
    6985 {
    6986    // Test condition (NB: bit 0 is always true) and clear flags for next time
    6987    if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
    6988       return;
    6989    window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
    6990 
    6991    // Set
    6992    window->Collapsed = collapsed;
     6518    if (ImGuiWindow* window = FindWindowByName(name))
     6519        SetWindowSize(window, size, cond);
     6520}
     6521
     6522void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
     6523{
     6524    // Test condition (NB: bit 0 is always true) and clear flags for next time
     6525    if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
     6526        return;
     6527    window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
     6528
     6529    // Set
     6530    window->Collapsed = collapsed;
     6531}
     6532
     6533void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size)
     6534{
     6535    IM_ASSERT(window->HitTestHoleSize.x == 0);     // We don't support multiple holes/hit test filters
     6536    window->HitTestHoleSize = ImVec2ih(size);
     6537    window->HitTestHoleOffset = ImVec2ih(pos - window->Pos);
    69936538}
    69946539
    69956540void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
    69966541{
    6997    SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
     6542    SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
    69986543}
    69996544
    70006545bool ImGui::IsWindowCollapsed()
    70016546{
    7002    ImGuiWindow* window = GetCurrentWindowRead();
    7003    return window->Collapsed;
     6547    ImGuiWindow* window = GetCurrentWindowRead();
     6548    return window->Collapsed;
    70046549}
    70056550
    70066551bool ImGui::IsWindowAppearing()
    70076552{
    7008    ImGuiWindow* window = GetCurrentWindowRead();
    7009    return window->Appearing;
     6553    ImGuiWindow* window = GetCurrentWindowRead();
     6554    return window->Appearing;
    70106555}
    70116556
    70126557void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
    70136558{
    7014    if (ImGuiWindow* window = FindWindowByName(name))
    7015       SetWindowCollapsed(window, collapsed, cond);
     6559    if (ImGuiWindow* window = FindWindowByName(name))
     6560        SetWindowCollapsed(window, collapsed, cond);
    70166561}
    70176562
    70186563void ImGui::SetWindowFocus()
    70196564{
    7020    FocusWindow(GImGui->CurrentWindow);
     6565    FocusWindow(GImGui->CurrentWindow);
    70216566}
    70226567
    70236568void ImGui::SetWindowFocus(const char* name)
    70246569{
    7025    if (name)
    7026    {
    7027       if (ImGuiWindow* window = FindWindowByName(name))
    7028          FocusWindow(window);
    7029    }
    7030    else
    7031    {
    7032       FocusWindow(NULL);
    7033    }
     6570    if (name)
     6571    {
     6572        if (ImGuiWindow* window = FindWindowByName(name))
     6573            FocusWindow(window);
     6574    }
     6575    else
     6576    {
     6577        FocusWindow(NULL);
     6578    }
    70346579}
    70356580
    70366581void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
    70376582{
    7038    ImGuiContext& g = *GImGui;
    7039    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
    7040    g.NextWindowData.PosVal = pos;
    7041    g.NextWindowData.PosPivotVal = pivot;
    7042    g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
     6583    ImGuiContext& g = *GImGui;
     6584    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
     6585    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;
     6586    g.NextWindowData.PosVal = pos;
     6587    g.NextWindowData.PosPivotVal = pivot;
     6588    g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
    70436589}
    70446590
    70456591void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
    70466592{
    7047    ImGuiContext& g = *GImGui;
    7048    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
    7049    g.NextWindowData.SizeVal = size;
    7050    g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
     6593    ImGuiContext& g = *GImGui;
     6594    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
     6595    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;
     6596    g.NextWindowData.SizeVal = size;
     6597    g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
    70516598}
    70526599
    70536600void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
    70546601{
    7055    ImGuiContext& g = *GImGui;
    7056    g.NextWindowData.SizeConstraintCond = ImGuiCond_Always;
    7057    g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
    7058    g.NextWindowData.SizeCallback = custom_callback;
    7059    g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
    7060 }
    7061 
     6602    ImGuiContext& g = *GImGui;
     6603    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
     6604    g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
     6605    g.NextWindowData.SizeCallback = custom_callback;
     6606    g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
     6607}
     6608
     6609// Content size = inner scrollable rectangle, padded with WindowPadding.
     6610// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
    70626611void ImGui::SetNextWindowContentSize(const ImVec2& size)
    70636612{
    7064    ImGuiContext& g = *GImGui;
    7065    g.NextWindowData.ContentSizeVal = size;  // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value.
    7066    g.NextWindowData.ContentSizeCond = ImGuiCond_Always;
     6613    ImGuiContext& g = *GImGui;
     6614    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;
     6615    g.NextWindowData.ContentSizeVal = size;
     6616}
     6617
     6618void ImGui::SetNextWindowScroll(const ImVec2& scroll)
     6619{
     6620    ImGuiContext& g = *GImGui;
     6621    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll;
     6622    g.NextWindowData.ScrollVal = scroll;
    70676623}
    70686624
    70696625void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
    70706626{
    7071    ImGuiContext& g = *GImGui;
    7072    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
    7073    g.NextWindowData.CollapsedVal = collapsed;
    7074    g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
     6627    ImGuiContext& g = *GImGui;
     6628    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
     6629    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;
     6630    g.NextWindowData.CollapsedVal = collapsed;
     6631    g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
    70756632}
    70766633
    70776634void ImGui::SetNextWindowFocus()
    70786635{
    7079    ImGuiContext& g = *GImGui;
    7080    g.NextWindowData.FocusCond = ImGuiCond_Always;   // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
     6636    ImGuiContext& g = *GImGui;
     6637    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;
    70816638}
    70826639
    70836640void ImGui::SetNextWindowBgAlpha(float alpha)
    70846641{
    7085    ImGuiContext& g = *GImGui;
    7086    g.NextWindowData.BgAlphaVal = alpha;
    7087    g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
    7088 }
    7089 
    7090 // In window space (not screen space!)
    7091 ImVec2 ImGui::GetContentRegionMax()
    7092 {
    7093    ImGuiWindow* window = GetCurrentWindowRead();
    7094    ImVec2 mx = window->ContentsRegionRect.Max;
    7095    if (window->DC.ColumnsSet)
    7096       mx.x = GetColumnOffset(window->DC.ColumnsSet->Current + 1) - window->WindowPadding.x;
    7097    return mx;
    7098 }
    7099 
    7100 ImVec2 ImGui::GetContentRegionAvail()
    7101 {
    7102    ImGuiWindow* window = GetCurrentWindowRead();
    7103    return GetContentRegionMax() - (window->DC.CursorPos - window->Pos);
    7104 }
    7105 
    7106 float ImGui::GetContentRegionAvailWidth()
    7107 {
    7108    return GetContentRegionAvail().x;
    7109 }
    7110 
    7111 // In window space (not screen space!)
    7112 ImVec2 ImGui::GetWindowContentRegionMin()
    7113 {
    7114    ImGuiWindow* window = GetCurrentWindowRead();
    7115    return window->ContentsRegionRect.Min;
    7116 }
    7117 
    7118 ImVec2 ImGui::GetWindowContentRegionMax()
    7119 {
    7120    ImGuiWindow* window = GetCurrentWindowRead();
    7121    return window->ContentsRegionRect.Max;
    7122 }
    7123 
    7124 float ImGui::GetWindowContentRegionWidth()
    7125 {
    7126    ImGuiWindow* window = GetCurrentWindowRead();
    7127    return window->ContentsRegionRect.Max.x - window->ContentsRegionRect.Min.x;
    7128 }
    7129 
    7130 float ImGui::GetTextLineHeight()
    7131 {
    7132    ImGuiContext& g = *GImGui;
    7133    return g.FontSize;
    7134 }
    7135 
    7136 float ImGui::GetTextLineHeightWithSpacing()
    7137 {
    7138    ImGuiContext& g = *GImGui;
    7139    return g.FontSize + g.Style.ItemSpacing.y;
    7140 }
    7141 
    7142 float ImGui::GetFrameHeight()
    7143 {
    7144    ImGuiContext& g = *GImGui;
    7145    return g.FontSize + g.Style.FramePadding.y * 2.0f;
    7146 }
    7147 
    7148 float ImGui::GetFrameHeightWithSpacing()
    7149 {
    7150    ImGuiContext& g = *GImGui;
    7151    return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
     6642    ImGuiContext& g = *GImGui;
     6643    g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;
     6644    g.NextWindowData.BgAlphaVal = alpha;
    71526645}
    71536646
    71546647ImDrawList* ImGui::GetWindowDrawList()
    71556648{
    7156    ImGuiWindow* window = GetCurrentWindow();
    7157    return window->DrawList;
     6649    ImGuiWindow* window = GetCurrentWindow();
     6650    return window->DrawList;
    71586651}
    71596652
    71606653ImFont* ImGui::GetFont()
    71616654{
    7162    return GImGui->Font;
     6655    return GImGui->Font;
    71636656}
    71646657
    71656658float ImGui::GetFontSize()
    71666659{
    7167    return GImGui->FontSize;
     6660    return GImGui->FontSize;
    71686661}
    71696662
    71706663ImVec2 ImGui::GetFontTexUvWhitePixel()
    71716664{
    7172    return GImGui->DrawListSharedData.TexUvWhitePixel;
     6665    return GImGui->DrawListSharedData.TexUvWhitePixel;
    71736666}
    71746667
    71756668void ImGui::SetWindowFontScale(float scale)
    71766669{
    7177    ImGuiContext& g = *GImGui;
    7178    ImGuiWindow* window = GetCurrentWindow();
    7179    window->FontWindowScale = scale;
    7180    g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
     6670    IM_ASSERT(scale > 0.0f);
     6671    ImGuiContext& g = *GImGui;
     6672    ImGuiWindow* window = GetCurrentWindow();
     6673    window->FontWindowScale = scale;
     6674    g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
     6675}
     6676
     6677void ImGui::ActivateItem(ImGuiID id)
     6678{
     6679    ImGuiContext& g = *GImGui;
     6680    g.NavNextActivateId = id;
     6681}
     6682
     6683// Note: this is storing in same stack as IDStack, so Push/Pop mismatch will be reported there.
     6684void ImGui::PushFocusScope(ImGuiID id)
     6685{
     6686    ImGuiContext& g = *GImGui;
     6687    ImGuiWindow* window = g.CurrentWindow;
     6688    window->IDStack.push_back(window->DC.NavFocusScopeIdCurrent);
     6689    window->DC.NavFocusScopeIdCurrent = id;
     6690}
     6691
     6692void ImGui::PopFocusScope()
     6693{
     6694    ImGuiContext& g = *GImGui;
     6695    ImGuiWindow* window = g.CurrentWindow;
     6696    window->DC.NavFocusScopeIdCurrent = window->IDStack.back();
     6697    window->IDStack.pop_back();
     6698}
     6699
     6700void ImGui::SetKeyboardFocusHere(int offset)
     6701{
     6702    IM_ASSERT(offset >= -1);    // -1 is allowed but not below
     6703    ImGuiContext& g = *GImGui;
     6704    ImGuiWindow* window = g.CurrentWindow;
     6705    g.FocusRequestNextWindow = window;
     6706    g.FocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset;
     6707    g.FocusRequestNextCounterTabStop = INT_MAX;
     6708}
     6709
     6710void ImGui::SetItemDefaultFocus()
     6711{
     6712    ImGuiContext& g = *GImGui;
     6713    ImGuiWindow* window = g.CurrentWindow;
     6714    if (!window->Appearing)
     6715        return;
     6716    if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
     6717    {
     6718        g.NavInitRequest = false;
     6719        g.NavInitResultId = g.NavWindow->DC.LastItemId;
     6720        g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
     6721        NavUpdateAnyRequestFlag();
     6722        if (!IsItemVisible())
     6723            SetScrollHereY();
     6724    }
     6725}
     6726
     6727void ImGui::SetStateStorage(ImGuiStorage* tree)
     6728{
     6729    ImGuiWindow* window = GImGui->CurrentWindow;
     6730    window->DC.StateStorage = tree ? tree : &window->StateStorage;
     6731}
     6732
     6733ImGuiStorage* ImGui::GetStateStorage()
     6734{
     6735    ImGuiWindow* window = GImGui->CurrentWindow;
     6736    return window->DC.StateStorage;
     6737}
     6738
     6739void ImGui::PushID(const char* str_id)
     6740{
     6741    ImGuiContext& g = *GImGui;
     6742    ImGuiWindow* window = g.CurrentWindow;
     6743    ImGuiID id = window->GetIDNoKeepAlive(str_id);
     6744    window->IDStack.push_back(id);
     6745}
     6746
     6747void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
     6748{
     6749    ImGuiContext& g = *GImGui;
     6750    ImGuiWindow* window = g.CurrentWindow;
     6751    ImGuiID id = window->GetIDNoKeepAlive(str_id_begin, str_id_end);
     6752    window->IDStack.push_back(id);
     6753}
     6754
     6755void ImGui::PushID(const void* ptr_id)
     6756{
     6757    ImGuiContext& g = *GImGui;
     6758    ImGuiWindow* window = g.CurrentWindow;
     6759    ImGuiID id = window->GetIDNoKeepAlive(ptr_id);
     6760    window->IDStack.push_back(id);
     6761}
     6762
     6763void ImGui::PushID(int int_id)
     6764{
     6765    ImGuiContext& g = *GImGui;
     6766    ImGuiWindow* window = g.CurrentWindow;
     6767    ImGuiID id = window->GetIDNoKeepAlive(int_id);
     6768    window->IDStack.push_back(id);
     6769}
     6770
     6771// Push a given id value ignoring the ID stack as a seed.
     6772void ImGui::PushOverrideID(ImGuiID id)
     6773{
     6774    ImGuiContext& g = *GImGui;
     6775    ImGuiWindow* window = g.CurrentWindow;
     6776    window->IDStack.push_back(id);
     6777}
     6778
     6779// Helper to avoid a common series of PushOverrideID -> GetID() -> PopID() call
     6780// (note that when using this pattern, TestEngine's "Stack Tool" will tend to not display the intermediate stack level.
     6781//  for that to work we would need to do PushOverrideID() -> ItemAdd() -> PopID() which would alter widget code a little more)
     6782ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
     6783{
     6784    ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
     6785    ImGui::KeepAliveID(id);
     6786#ifdef IMGUI_ENABLE_TEST_ENGINE
     6787    ImGuiContext& g = *GImGui;
     6788    IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
     6789#endif
     6790    return id;
     6791}
     6792
     6793void ImGui::PopID()
     6794{
     6795    ImGuiWindow* window = GImGui->CurrentWindow;
     6796    window->IDStack.pop_back();
     6797}
     6798
     6799ImGuiID ImGui::GetID(const char* str_id)
     6800{
     6801    ImGuiWindow* window = GImGui->CurrentWindow;
     6802    return window->GetID(str_id);
     6803}
     6804
     6805ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
     6806{
     6807    ImGuiWindow* window = GImGui->CurrentWindow;
     6808    return window->GetID(str_id_begin, str_id_end);
     6809}
     6810
     6811ImGuiID ImGui::GetID(const void* ptr_id)
     6812{
     6813    ImGuiWindow* window = GImGui->CurrentWindow;
     6814    return window->GetID(ptr_id);
     6815}
     6816
     6817bool ImGui::IsRectVisible(const ImVec2& size)
     6818{
     6819    ImGuiWindow* window = GImGui->CurrentWindow;
     6820    return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
     6821}
     6822
     6823bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
     6824{
     6825    ImGuiWindow* window = GImGui->CurrentWindow;
     6826    return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
     6827}
     6828
     6829
     6830//-----------------------------------------------------------------------------
     6831// [SECTION] ERROR CHECKING
     6832//-----------------------------------------------------------------------------
     6833
     6834// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
     6835// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
     6836// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
     6837// may see different structures than what imgui.cpp sees, which is problematic.
     6838// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui.
     6839bool 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)
     6840{
     6841    bool error = false;
     6842    if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); }
     6843    if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
     6844    if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
     6845    if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
     6846    if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
     6847    if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
     6848    if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); }
     6849    return !error;
     6850}
     6851
     6852static void ImGui::ErrorCheckNewFrameSanityChecks()
     6853{
     6854    ImGuiContext& g = *GImGui;
     6855
     6856    // Check user IM_ASSERT macro
     6857    // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means you assert macro is incorrectly defined!
     6858    //  If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block.
     6859    //  This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.)
     6860    // #define IM_ASSERT(EXPR)   SomeCode(EXPR); SomeMoreCode();                    // Wrong!
     6861    // #define IM_ASSERT(EXPR)   do { SomeCode(EXPR); SomeMoreCode(); } while (0)   // Correct!
     6862    if (true) IM_ASSERT(1); else IM_ASSERT(0);
     6863
     6864    // Check user data
     6865    // (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)
     6866    IM_ASSERT(g.Initialized);
     6867    IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0)              && "Need a positive DeltaTime!");
     6868    IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount)  && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
     6869    IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f  && "Invalid DisplaySize value!");
     6870    IM_ASSERT(g.IO.Fonts->Fonts.Size > 0                                && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
     6871    IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()                          && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
     6872    IM_ASSERT(g.Style.CurveTessellationTol > 0.0f                       && "Invalid style setting!");
     6873    IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f                      && "Invalid style setting!");
     6874    IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f            && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!");
     6875    IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
     6876    IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
     6877    for (int n = 0; n < ImGuiKey_COUNT; n++)
     6878        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)");
     6879
     6880    // Perform simple check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP)
     6881    if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
     6882        IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
     6883
     6884    // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
     6885    if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
     6886        g.IO.ConfigWindowsResizeFromEdges = false;
     6887}
     6888
     6889static void ImGui::ErrorCheckEndFrameSanityChecks()
     6890{
     6891    ImGuiContext& g = *GImGui;
     6892
     6893    // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame()
     6894    // One possible reason leading to this assert is that your back-ends update inputs _AFTER_ NewFrame().
     6895    const ImGuiKeyModFlags expected_key_mod_flags = GetMergedKeyModFlags();
     6896    IM_ASSERT(g.IO.KeyMods == expected_key_mod_flags && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
     6897    IM_UNUSED(expected_key_mod_flags);
     6898
     6899    // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
     6900    // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
     6901    if (g.CurrentWindowStack.Size != 1)
     6902    {
     6903        if (g.CurrentWindowStack.Size > 1)
     6904        {
     6905            IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
     6906            while (g.CurrentWindowStack.Size > 1)
     6907                End();
     6908        }
     6909        else
     6910        {
     6911            IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
     6912        }
     6913    }
     6914}
     6915
     6916// Save and compare stack sizes on Begin()/End() to detect usage errors
     6917// Begin() calls this with write=true
     6918// End() calls this with write=false
     6919static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write)
     6920{
     6921    ImGuiContext& g = *GImGui;
     6922    short* p = &window->DC.StackSizesBackup[0];
     6923
     6924    // Window stacks
     6925    // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
     6926    { int n = window->IDStack.Size;       if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!");   p++; }    // Too few or too many PopID()/TreePop()
     6927    { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!");                p++; }    // Too few or too many EndGroup()
     6928
     6929    // Global stacks
     6930    // 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.
     6931    { int n = g.BeginPopupStack.Size;     if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup()
     6932    { int n = g.ColorModifiers.Size;      if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!");       p++; }    // Too few or too many PopStyleColor()
     6933    { int n = g.StyleModifiers.Size;      if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!");           p++; }    // Too few or too many PopStyleVar()
     6934    { int n = g.FontStack.Size;           if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!");                   p++; }    // Too few or too many PopFont()
     6935    IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
     6936}
     6937
     6938
     6939//-----------------------------------------------------------------------------
     6940// [SECTION] LAYOUT
     6941//-----------------------------------------------------------------------------
     6942// - ItemSize()
     6943// - ItemAdd()
     6944// - SameLine()
     6945// - GetCursorScreenPos()
     6946// - SetCursorScreenPos()
     6947// - GetCursorPos(), GetCursorPosX(), GetCursorPosY()
     6948// - SetCursorPos(), SetCursorPosX(), SetCursorPosY()
     6949// - GetCursorStartPos()
     6950// - Indent()
     6951// - Unindent()
     6952// - SetNextItemWidth()
     6953// - PushItemWidth()
     6954// - PushMultiItemsWidths()
     6955// - PopItemWidth()
     6956// - CalcItemWidth()
     6957// - CalcItemSize()
     6958// - GetTextLineHeight()
     6959// - GetTextLineHeightWithSpacing()
     6960// - GetFrameHeight()
     6961// - GetFrameHeightWithSpacing()
     6962// - GetContentRegionMax()
     6963// - GetContentRegionMaxAbs() [Internal]
     6964// - GetContentRegionAvail(),
     6965// - GetWindowContentRegionMin(), GetWindowContentRegionMax()
     6966// - GetWindowContentRegionWidth()
     6967// - BeginGroup()
     6968// - EndGroup()
     6969// Also see in imgui_widgets: tab bars, columns.
     6970//-----------------------------------------------------------------------------
     6971
     6972// Advance cursor given item size for layout.
     6973// Register minimum needed size so it can extend the bounding box used for auto-fit calculation.
     6974// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.
     6975void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
     6976{
     6977    ImGuiContext& g = *GImGui;
     6978    ImGuiWindow* window = g.CurrentWindow;
     6979    if (window->SkipItems)
     6980        return;
     6981
     6982    // We increase the height in this function to accommodate for baseline offset.
     6983    // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
     6984    // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
     6985    const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
     6986    const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y);
     6987
     6988    // Always align ourselves on pixel boundaries
     6989    //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]
     6990    window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
     6991    window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
     6992    window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);    // Next line
     6993    window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);        // Next line
     6994    window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
     6995    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
     6996    //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
     6997
     6998    window->DC.PrevLineSize.y = line_height;
     6999    window->DC.CurrLineSize.y = 0.0f;
     7000    window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
     7001    window->DC.CurrLineTextBaseOffset = 0.0f;
     7002
     7003    // Horizontal layout mode
     7004    if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
     7005        SameLine();
     7006}
     7007
     7008void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
     7009{
     7010    ItemSize(bb.GetSize(), text_baseline_y);
     7011}
     7012
     7013// Declare item bounding box for clipping and interaction.
     7014// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
     7015// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
     7016bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
     7017{
     7018    ImGuiContext& g = *GImGui;
     7019    ImGuiWindow* window = g.CurrentWindow;
     7020
     7021    if (id != 0)
     7022    {
     7023        // Navigation processing runs prior to clipping early-out
     7024        //  (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
     7025        //  (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
     7026        //      unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
     7027        //      thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
     7028        //      We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
     7029        //      to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
     7030        // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
     7031        // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
     7032        window->DC.NavLayerActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
     7033        if (g.NavId == id || g.NavAnyRequest)
     7034            if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
     7035                if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
     7036                    NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
     7037
     7038        // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
     7039#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
     7040        if (id == g.DebugItemPickerBreakId)
     7041        {
     7042            IM_DEBUG_BREAK();
     7043            g.DebugItemPickerBreakId = 0;
     7044        }
     7045#endif
     7046    }
     7047
     7048    // Equivalent to calling SetLastItemData()
     7049    window->DC.LastItemId = id;
     7050    window->DC.LastItemRect = bb;
     7051    window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
     7052    g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
     7053
     7054#ifdef IMGUI_ENABLE_TEST_ENGINE
     7055    if (id != 0)
     7056        IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id);
     7057#endif
     7058
     7059    // Clipping test
     7060    const bool is_clipped = IsClippedEx(bb, id, false);
     7061    if (is_clipped)
     7062        return false;
     7063    //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
     7064
     7065    // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
     7066    if (IsMouseHoveringRect(bb.Min, bb.Max))
     7067        window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
     7068    return true;
     7069}
     7070
     7071// Gets back to previous line and continue with horizontal layout
     7072//      offset_from_start_x == 0 : follow right after previous item
     7073//      offset_from_start_x != 0 : align to specified x position (relative to window/group left)
     7074//      spacing_w < 0            : use default spacing if pos_x == 0, no spacing if pos_x != 0
     7075//      spacing_w >= 0           : enforce spacing amount
     7076void ImGui::SameLine(float offset_from_start_x, float spacing_w)
     7077{
     7078    ImGuiWindow* window = GetCurrentWindow();
     7079    if (window->SkipItems)
     7080        return;
     7081
     7082    ImGuiContext& g = *GImGui;
     7083    if (offset_from_start_x != 0.0f)
     7084    {
     7085        if (spacing_w < 0.0f) spacing_w = 0.0f;
     7086        window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
     7087        window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
     7088    }
     7089    else
     7090    {
     7091        if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
     7092        window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
     7093        window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
     7094    }
     7095    window->DC.CurrLineSize = window->DC.PrevLineSize;
     7096    window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
     7097}
     7098
     7099ImVec2 ImGui::GetCursorScreenPos()
     7100{
     7101    ImGuiWindow* window = GetCurrentWindowRead();
     7102    return window->DC.CursorPos;
     7103}
     7104
     7105void ImGui::SetCursorScreenPos(const ImVec2& pos)
     7106{
     7107    ImGuiWindow* window = GetCurrentWindow();
     7108    window->DC.CursorPos = pos;
     7109    window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
    71817110}
    71827111
     
    71857114ImVec2 ImGui::GetCursorPos()
    71867115{
    7187    ImGuiWindow* window = GetCurrentWindowRead();
    7188    return window->DC.CursorPos - window->Pos + window->Scroll;
     7116    ImGuiWindow* window = GetCurrentWindowRead();
     7117    return window->DC.CursorPos - window->Pos + window->Scroll;
    71897118}
    71907119
    71917120float ImGui::GetCursorPosX()
    71927121{
    7193    ImGuiWindow* window = GetCurrentWindowRead();
    7194    return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
     7122    ImGuiWindow* window = GetCurrentWindowRead();
     7123    return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
    71957124}
    71967125
    71977126float ImGui::GetCursorPosY()
    71987127{
    7199    ImGuiWindow* window = GetCurrentWindowRead();
    7200    return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
     7128    ImGuiWindow* window = GetCurrentWindowRead();
     7129    return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
    72017130}
    72027131
    72037132void ImGui::SetCursorPos(const ImVec2& local_pos)
    72047133{
    7205    ImGuiWindow* window = GetCurrentWindow();
    7206    window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
    7207    window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
     7134    ImGuiWindow* window = GetCurrentWindow();
     7135    window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
     7136    window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
    72087137}
    72097138
    72107139void ImGui::SetCursorPosX(float x)
    72117140{
    7212    ImGuiWindow* window = GetCurrentWindow();
    7213    window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
    7214    window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
     7141    ImGuiWindow* window = GetCurrentWindow();
     7142    window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
     7143    window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
    72157144}
    72167145
    72177146void ImGui::SetCursorPosY(float y)
    72187147{
    7219    ImGuiWindow* window = GetCurrentWindow();
    7220    window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
    7221    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
     7148    ImGuiWindow* window = GetCurrentWindow();
     7149    window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
     7150    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
    72227151}
    72237152
    72247153ImVec2 ImGui::GetCursorStartPos()
    72257154{
    7226    ImGuiWindow* window = GetCurrentWindowRead();
    7227    return window->DC.CursorStartPos - window->Pos;
    7228 }
    7229 
    7230 ImVec2 ImGui::GetCursorScreenPos()
    7231 {
    7232    ImGuiWindow* window = GetCurrentWindowRead();
    7233    return window->DC.CursorPos;
    7234 }
    7235 
    7236 void ImGui::SetCursorScreenPos(const ImVec2& screen_pos)
    7237 {
    7238    ImGuiWindow* window = GetCurrentWindow();
    7239    window->DC.CursorPos = screen_pos;
    7240    window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
     7155    ImGuiWindow* window = GetCurrentWindowRead();
     7156    return window->DC.CursorStartPos - window->Pos;
     7157}
     7158
     7159void ImGui::Indent(float indent_w)
     7160{
     7161    ImGuiContext& g = *GImGui;
     7162    ImGuiWindow* window = GetCurrentWindow();
     7163    window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
     7164    window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
     7165}
     7166
     7167void ImGui::Unindent(float indent_w)
     7168{
     7169    ImGuiContext& g = *GImGui;
     7170    ImGuiWindow* window = GetCurrentWindow();
     7171    window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
     7172    window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
     7173}
     7174
     7175// Affect large frame+labels widgets only.
     7176void ImGui::SetNextItemWidth(float item_width)
     7177{
     7178    ImGuiContext& g = *GImGui;
     7179    g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
     7180    g.NextItemData.Width = item_width;
     7181}
     7182
     7183void ImGui::PushItemWidth(float item_width)
     7184{
     7185    ImGuiContext& g = *GImGui;
     7186    ImGuiWindow* window = g.CurrentWindow;
     7187    window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
     7188    window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
     7189    g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
     7190}
     7191
     7192void ImGui::PushMultiItemsWidths(int components, float w_full)
     7193{
     7194    ImGuiContext& g = *GImGui;
     7195    ImGuiWindow* window = g.CurrentWindow;
     7196    const ImGuiStyle& style = g.Style;
     7197    const float w_item_one  = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));
     7198    const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));
     7199    window->DC.ItemWidthStack.push_back(w_item_last);
     7200    for (int i = 0; i < components - 1; i++)
     7201        window->DC.ItemWidthStack.push_back(w_item_one);
     7202    window->DC.ItemWidth = window->DC.ItemWidthStack.back();
     7203    g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
     7204}
     7205
     7206void ImGui::PopItemWidth()
     7207{
     7208    ImGuiWindow* window = GetCurrentWindow();
     7209    window->DC.ItemWidthStack.pop_back();
     7210    window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
     7211}
     7212
     7213// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
     7214// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
     7215float ImGui::CalcItemWidth()
     7216{
     7217    ImGuiContext& g = *GImGui;
     7218    ImGuiWindow* window = g.CurrentWindow;
     7219    float w;
     7220    if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
     7221        w = g.NextItemData.Width;
     7222    else
     7223        w = window->DC.ItemWidth;
     7224    if (w < 0.0f)
     7225    {
     7226        float region_max_x = GetContentRegionMaxAbs().x;
     7227        w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
     7228    }
     7229    w = IM_FLOOR(w);
     7230    return w;
     7231}
     7232
     7233// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
     7234// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
     7235// Note that only CalcItemWidth() is publicly exposed.
     7236// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
     7237ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
     7238{
     7239    ImGuiWindow* window = GImGui->CurrentWindow;
     7240
     7241    ImVec2 region_max;
     7242    if (size.x < 0.0f || size.y < 0.0f)
     7243        region_max = GetContentRegionMaxAbs();
     7244
     7245    if (size.x == 0.0f)
     7246        size.x = default_w;
     7247    else if (size.x < 0.0f)
     7248        size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
     7249
     7250    if (size.y == 0.0f)
     7251        size.y = default_h;
     7252    else if (size.y < 0.0f)
     7253        size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
     7254
     7255    return size;
     7256}
     7257
     7258float ImGui::GetTextLineHeight()
     7259{
     7260    ImGuiContext& g = *GImGui;
     7261    return g.FontSize;
     7262}
     7263
     7264float ImGui::GetTextLineHeightWithSpacing()
     7265{
     7266    ImGuiContext& g = *GImGui;
     7267    return g.FontSize + g.Style.ItemSpacing.y;
     7268}
     7269
     7270float ImGui::GetFrameHeight()
     7271{
     7272    ImGuiContext& g = *GImGui;
     7273    return g.FontSize + g.Style.FramePadding.y * 2.0f;
     7274}
     7275
     7276float ImGui::GetFrameHeightWithSpacing()
     7277{
     7278    ImGuiContext& g = *GImGui;
     7279    return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
     7280}
     7281
     7282// 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!
     7283
     7284// FIXME: This is in window space (not screen space!).
     7285ImVec2 ImGui::GetContentRegionMax()
     7286{
     7287    ImGuiContext& g = *GImGui;
     7288    ImGuiWindow* window = g.CurrentWindow;
     7289    ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
     7290    if (window->DC.CurrentColumns)
     7291        mx.x = window->WorkRect.Max.x - window->Pos.x;
     7292    return mx;
     7293}
     7294
     7295// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
     7296ImVec2 ImGui::GetContentRegionMaxAbs()
     7297{
     7298    ImGuiContext& g = *GImGui;
     7299    ImGuiWindow* window = g.CurrentWindow;
     7300    ImVec2 mx = window->ContentRegionRect.Max;
     7301    if (window->DC.CurrentColumns)
     7302        mx.x = window->WorkRect.Max.x;
     7303    return mx;
     7304}
     7305
     7306ImVec2 ImGui::GetContentRegionAvail()
     7307{
     7308    ImGuiWindow* window = GImGui->CurrentWindow;
     7309    return GetContentRegionMaxAbs() - window->DC.CursorPos;
     7310}
     7311
     7312// In window space (not screen space!)
     7313ImVec2 ImGui::GetWindowContentRegionMin()
     7314{
     7315    ImGuiWindow* window = GImGui->CurrentWindow;
     7316    return window->ContentRegionRect.Min - window->Pos;
     7317}
     7318
     7319ImVec2 ImGui::GetWindowContentRegionMax()
     7320{
     7321    ImGuiWindow* window = GImGui->CurrentWindow;
     7322    return window->ContentRegionRect.Max - window->Pos;
     7323}
     7324
     7325float ImGui::GetWindowContentRegionWidth()
     7326{
     7327    ImGuiWindow* window = GImGui->CurrentWindow;
     7328    return window->ContentRegionRect.GetWidth();
     7329}
     7330
     7331// 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.)
     7332// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
     7333void ImGui::BeginGroup()
     7334{
     7335    ImGuiContext& g = *GImGui;
     7336    ImGuiWindow* window = g.CurrentWindow;
     7337
     7338    window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
     7339    ImGuiGroupData& group_data = window->DC.GroupStack.back();
     7340    group_data.BackupCursorPos = window->DC.CursorPos;
     7341    group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
     7342    group_data.BackupIndent = window->DC.Indent;
     7343    group_data.BackupGroupOffset = window->DC.GroupOffset;
     7344    group_data.BackupCurrLineSize = window->DC.CurrLineSize;
     7345    group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
     7346    group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
     7347    group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
     7348    group_data.EmitItem = true;
     7349
     7350    window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
     7351    window->DC.Indent = window->DC.GroupOffset;
     7352    window->DC.CursorMaxPos = window->DC.CursorPos;
     7353    window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
     7354    if (g.LogEnabled)
     7355        g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
     7356}
     7357
     7358void ImGui::EndGroup()
     7359{
     7360    ImGuiContext& g = *GImGui;
     7361    ImGuiWindow* window = g.CurrentWindow;
     7362    IM_ASSERT(window->DC.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls
     7363
     7364    ImGuiGroupData& group_data = window->DC.GroupStack.back();
     7365
     7366    ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
     7367
     7368    window->DC.CursorPos = group_data.BackupCursorPos;
     7369    window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
     7370    window->DC.Indent = group_data.BackupIndent;
     7371    window->DC.GroupOffset = group_data.BackupGroupOffset;
     7372    window->DC.CurrLineSize = group_data.BackupCurrLineSize;
     7373    window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
     7374    if (g.LogEnabled)
     7375        g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
     7376
     7377    if (!group_data.EmitItem)
     7378    {
     7379        window->DC.GroupStack.pop_back();
     7380        return;
     7381    }
     7382
     7383    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.
     7384    ItemSize(group_bb.GetSize());
     7385    ItemAdd(group_bb, 0);
     7386
     7387    // 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.
     7388    // 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.
     7389    // Also if you grep for LastItemId you'll notice it is only used in that context.
     7390    // (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.)
     7391    const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
     7392    const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);
     7393    if (group_contains_curr_active_id)
     7394        window->DC.LastItemId = g.ActiveId;
     7395    else if (group_contains_prev_active_id)
     7396        window->DC.LastItemId = g.ActiveIdPreviousFrame;
     7397    window->DC.LastItemRect = group_bb;
     7398
     7399    // Forward Edited flag
     7400    if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
     7401        window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
     7402
     7403    // Forward Deactivated flag
     7404    window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
     7405    if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
     7406        window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
     7407
     7408    window->DC.GroupStack.pop_back();
     7409    //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255));   // [Debug]
     7410}
     7411
     7412
     7413//-----------------------------------------------------------------------------
     7414// [SECTION] SCROLLING
     7415//-----------------------------------------------------------------------------
     7416
     7417// Helper to snap on edges when aiming at an item very close to the edge,
     7418// So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling.
     7419// When we refactor the scrolling API this may be configurable with a flag?
     7420// Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default.
     7421static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
     7422{
     7423    if (target <= snap_min + snap_threshold)
     7424        return ImLerp(snap_min, target, center_ratio);
     7425    if (target >= snap_max - snap_threshold)
     7426        return ImLerp(target, snap_max, center_ratio);
     7427    return target;
     7428}
     7429
     7430static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
     7431{
     7432    ImVec2 scroll = window->Scroll;
     7433    if (window->ScrollTarget.x < FLT_MAX)
     7434    {
     7435        float center_x_ratio = window->ScrollTargetCenterRatio.x;
     7436        float scroll_target_x = window->ScrollTarget.x;
     7437        float snap_x_min = 0.0f;
     7438        float snap_x_max = window->ScrollMax.x + window->Size.x;
     7439        if (window->ScrollTargetEdgeSnapDist.x > 0.0f)
     7440            scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio);
     7441        scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - window->ScrollbarSizes.x);
     7442    }
     7443    if (window->ScrollTarget.y < FLT_MAX)
     7444    {
     7445        float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
     7446        float center_y_ratio = window->ScrollTargetCenterRatio.y;
     7447        float scroll_target_y = window->ScrollTarget.y;
     7448        float snap_y_min = 0.0f;
     7449        float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height;
     7450        if (window->ScrollTargetEdgeSnapDist.y > 0.0f)
     7451            scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio);
     7452        scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height);
     7453    }
     7454    scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f));
     7455    scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f));
     7456    if (!window->Collapsed && !window->SkipItems)
     7457    {
     7458        scroll.x = ImMin(scroll.x, window->ScrollMax.x);
     7459        scroll.y = ImMin(scroll.y, window->ScrollMax.y);
     7460    }
     7461    return scroll;
     7462}
     7463
     7464// Scroll to keep newly navigated item fully into view
     7465ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
     7466{
     7467    ImGuiContext& g = *GImGui;
     7468    ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
     7469    //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
     7470
     7471    ImVec2 delta_scroll;
     7472    if (!window_rect.Contains(item_rect))
     7473    {
     7474        if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
     7475            SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x - g.Style.ItemSpacing.x, 0.0f);
     7476        else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
     7477            SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
     7478        if (item_rect.Min.y < window_rect.Min.y)
     7479            SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
     7480        else if (item_rect.Max.y >= window_rect.Max.y)
     7481            SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
     7482
     7483        ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
     7484        delta_scroll = next_scroll - window->Scroll;
     7485    }
     7486
     7487    // Also scroll parent window to keep us into view if necessary
     7488    if (window->Flags & ImGuiWindowFlags_ChildWindow)
     7489        delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll));
     7490
     7491    return delta_scroll;
    72417492}
    72427493
    72437494float ImGui::GetScrollX()
    72447495{
    7245    return GImGui->CurrentWindow->Scroll.x;
     7496    ImGuiWindow* window = GImGui->CurrentWindow;
     7497    return window->Scroll.x;
    72467498}
    72477499
    72487500float ImGui::GetScrollY()
    72497501{
    7250    return GImGui->CurrentWindow->Scroll.y;
     7502    ImGuiWindow* window = GImGui->CurrentWindow;
     7503    return window->Scroll.y;
    72517504}
    72527505
    72537506float ImGui::GetScrollMaxX()
    72547507{
    7255    return GetScrollMaxX(GImGui->CurrentWindow);
     7508    ImGuiWindow* window = GImGui->CurrentWindow;
     7509    return window->ScrollMax.x;
    72567510}
    72577511
    72587512float ImGui::GetScrollMaxY()
    72597513{
    7260    return GetScrollMaxY(GImGui->CurrentWindow);
     7514    ImGuiWindow* window = GImGui->CurrentWindow;
     7515    return window->ScrollMax.y;
     7516}
     7517
     7518void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x)
     7519{
     7520    window->ScrollTarget.x = scroll_x;
     7521    window->ScrollTargetCenterRatio.x = 0.0f;
     7522    window->ScrollTargetEdgeSnapDist.x = 0.0f;
     7523}
     7524
     7525void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y)
     7526{
     7527    window->ScrollTarget.y = scroll_y;
     7528    window->ScrollTargetCenterRatio.y = 0.0f;
     7529    window->ScrollTargetEdgeSnapDist.y = 0.0f;
    72617530}
    72627531
    72637532void ImGui::SetScrollX(float scroll_x)
    72647533{
    7265    ImGuiWindow* window = GetCurrentWindow();
    7266    window->ScrollTarget.x = scroll_x;
    7267    window->ScrollTargetCenterRatio.x = 0.0f;
     7534    ImGuiContext& g = *GImGui;
     7535    SetScrollX(g.CurrentWindow, scroll_x);
    72687536}
    72697537
    72707538void ImGui::SetScrollY(float scroll_y)
    72717539{
    7272    ImGuiWindow* window = GetCurrentWindow();
    7273    window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY
    7274    window->ScrollTargetCenterRatio.y = 0.0f;
    7275 }
    7276 
    7277 void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio)
    7278 {
    7279    // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
    7280    ImGuiWindow* window = GetCurrentWindow();
    7281    IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
    7282    window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y);
    7283    window->ScrollTargetCenterRatio.y = center_y_ratio;
    7284 
    7285    // Minor hack to to make scrolling to top/bottom of window take account of WindowPadding, it looks more right to the user this way
    7286    if (center_y_ratio <= 0.0f && window->ScrollTarget.y <= window->WindowPadding.y)
    7287       window->ScrollTarget.y = 0.0f;
    7288    else if (center_y_ratio >= 1.0f && window->ScrollTarget.y >= window->SizeContents.y - window->WindowPadding.y + GImGui->Style.ItemSpacing.y)
    7289       window->ScrollTarget.y = window->SizeContents.y;
     7540    ImGuiContext& g = *GImGui;
     7541    SetScrollY(g.CurrentWindow, scroll_y);
     7542}
     7543
     7544// Note that a local position will vary depending on initial scroll value,
     7545// This is a little bit confusing so bear with us:
     7546//  - local_pos = (absolution_pos - window->Pos)
     7547//  - So local_x/local_y are 0.0f for a position at the upper-left corner of a window,
     7548//    and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area.
     7549//  - They mostly exists because of legacy API.
     7550// Following the rules above, when trying to work with scrolling code, consider that:
     7551//  - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect!
     7552//  - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense
     7553// 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
     7554void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
     7555{
     7556    IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
     7557    window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); // Convert local position to scroll offset
     7558    window->ScrollTargetCenterRatio.x = center_x_ratio;
     7559    window->ScrollTargetEdgeSnapDist.x = 0.0f;
     7560}
     7561
     7562void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
     7563{
     7564    IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
     7565    local_y -= window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect
     7566    window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset
     7567    window->ScrollTargetCenterRatio.y = center_y_ratio;
     7568    window->ScrollTargetEdgeSnapDist.y = 0.0f;
     7569}
     7570
     7571void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
     7572{
     7573    ImGuiContext& g = *GImGui;
     7574    SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);
     7575}
     7576
     7577void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
     7578{
     7579    ImGuiContext& g = *GImGui;
     7580    SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);
     7581}
     7582
     7583// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
     7584void ImGui::SetScrollHereX(float center_x_ratio)
     7585{
     7586    ImGuiContext& g = *GImGui;
     7587    ImGuiWindow* window = g.CurrentWindow;
     7588    float spacing_x = g.Style.ItemSpacing.x;
     7589    float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio);
     7590    SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
     7591
     7592    // Tweak: snap on edges when aiming at an item very close to the edge
     7593    window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x);
    72907594}
    72917595
    72927596// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
    7293 void ImGui::SetScrollHere(float center_y_ratio)
    7294 {
    7295    ImGuiWindow* window = GetCurrentWindow();
    7296    float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space
    7297    target_y += (window->DC.PrevLineHeight * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line.
    7298    SetScrollFromPosY(target_y, center_y_ratio);
    7299 }
    7300 
    7301 void ImGui::ActivateItem(ImGuiID id)
    7302 {
    7303    ImGuiContext& g = *GImGui;
    7304    g.NavNextActivateId = id;
    7305 }
    7306 
    7307 void ImGui::SetKeyboardFocusHere(int offset)
    7308 {
    7309    IM_ASSERT(offset >= -1);    // -1 is allowed but not below
    7310    ImGuiWindow* window = GetCurrentWindow();
    7311    window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset;
    7312    window->FocusIdxTabRequestNext = INT_MAX;
    7313 }
    7314 
    7315 void ImGui::SetItemDefaultFocus()
    7316 {
    7317    ImGuiContext& g = *GImGui;
    7318    ImGuiWindow* window = g.CurrentWindow;
    7319    if (!window->Appearing)
    7320       return;
    7321    if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
    7322    {
    7323       g.NavInitRequest = false;
    7324       g.NavInitResultId = g.NavWindow->DC.LastItemId;
    7325       g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
    7326       NavUpdateAnyRequestFlag();
    7327       if (!IsItemVisible())
    7328          SetScrollHere();
    7329    }
    7330 }
    7331 
    7332 void ImGui::SetStateStorage(ImGuiStorage* tree)
    7333 {
    7334    ImGuiWindow* window = GetCurrentWindow();
    7335    window->DC.StateStorage = tree ? tree : &window->StateStorage;
    7336 }
    7337 
    7338 ImGuiStorage* ImGui::GetStateStorage()
    7339 {
    7340    ImGuiWindow* window = GetCurrentWindowRead();
    7341    return window->DC.StateStorage;
    7342 }
    7343 
    7344 void ImGui::TextV(const char* fmt, va_list args)
    7345 {
    7346    ImGuiWindow* window = GetCurrentWindow();
    7347    if (window->SkipItems)
    7348       return;
    7349 
    7350    ImGuiContext& g = *GImGui;
    7351    const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
    7352    TextUnformatted(g.TempBuffer, text_end);
    7353 }
    7354 
    7355 void ImGui::Text(const char* fmt, ...)
    7356 {
    7357    va_list args;
    7358    va_start(args, fmt);
    7359    TextV(fmt, args);
    7360    va_end(args);
    7361 }
    7362 
    7363 void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)
    7364 {
    7365    PushStyleColor(ImGuiCol_Text, col);
    7366    TextV(fmt, args);
    7367    PopStyleColor();
    7368 }
    7369 
    7370 void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
    7371 {
    7372    va_list args;
    7373    va_start(args, fmt);
    7374    TextColoredV(col, fmt, args);
    7375    va_end(args);
    7376 }
    7377 
    7378 void ImGui::TextDisabledV(const char* fmt, va_list args)
    7379 {
    7380    PushStyleColor(ImGuiCol_Text, GImGui->Style.Colors[ImGuiCol_TextDisabled]);
    7381    TextV(fmt, args);
    7382    PopStyleColor();
    7383 }
    7384 
    7385 void ImGui::TextDisabled(const char* fmt, ...)
    7386 {
    7387    va_list args;
    7388    va_start(args, fmt);
    7389    TextDisabledV(fmt, args);
    7390    va_end(args);
    7391 }
    7392 
    7393 void ImGui::TextWrappedV(const char* fmt, va_list args)
    7394 {
    7395    bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f);    // Keep existing wrap position is one ia already set
    7396    if (need_wrap) PushTextWrapPos(0.0f);
    7397    TextV(fmt, args);
    7398    if (need_wrap) PopTextWrapPos();
    7399 }
    7400 
    7401 void ImGui::TextWrapped(const char* fmt, ...)
    7402 {
    7403    va_list args;
    7404    va_start(args, fmt);
    7405    TextWrappedV(fmt, args);
    7406    va_end(args);
    7407 }
    7408 
    7409 void ImGui::TextUnformatted(const char* text, const char* text_end)
    7410 {
    7411    ImGuiWindow* window = GetCurrentWindow();
    7412    if (window->SkipItems)
    7413       return;
    7414 
    7415    ImGuiContext& g = *GImGui;
    7416    IM_ASSERT(text != NULL);
    7417    const char* text_begin = text;
    7418    if (text_end == NULL)
    7419       text_end = text + strlen(text); // FIXME-OPT
    7420 
    7421    const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset);
    7422    const float wrap_pos_x = window->DC.TextWrapPos;
    7423    const bool wrap_enabled = wrap_pos_x >= 0.0f;
    7424    if (text_end - text > 2000 && !wrap_enabled)
    7425    {
    7426       // Long text!
    7427       // Perform manual coarse clipping to optimize for long multi-line text
    7428       // From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.
    7429       // We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line.
    7430       const char* line = text;
    7431       const float line_height = GetTextLineHeight();
    7432       const ImRect clip_rect = window->ClipRect;
    7433       ImVec2 text_size(0, 0);
    7434 
    7435       if (text_pos.y <= clip_rect.Max.y)
    7436       {
    7437          ImVec2 pos = text_pos;
    7438 
    7439          // Lines to skip (can't skip when logging text)
    7440          if (!g.LogEnabled)
    7441          {
    7442             int lines_skippable = (int)((clip_rect.Min.y - text_pos.y) / line_height);
    7443             if (lines_skippable > 0)
     7597void ImGui::SetScrollHereY(float center_y_ratio)
     7598{
     7599    ImGuiContext& g = *GImGui;
     7600    ImGuiWindow* window = g.CurrentWindow;
     7601    float spacing_y = g.Style.ItemSpacing.y;
     7602    float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
     7603    SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos
     7604
     7605    // Tweak: snap on edges when aiming at an item very close to the edge
     7606    window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y);
     7607}
     7608
     7609//-----------------------------------------------------------------------------
     7610// [SECTION] TOOLTIPS
     7611//-----------------------------------------------------------------------------
     7612
     7613void ImGui::BeginTooltip()
     7614{
     7615    BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None);
     7616}
     7617
     7618void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags)
     7619{
     7620    ImGuiContext& g = *GImGui;
     7621
     7622    if (g.DragDropWithinSource || g.DragDropWithinTarget)
     7623    {
     7624        // 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)
     7625        // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor.
     7626        // 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.
     7627        //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;
     7628        ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale);
     7629        SetNextWindowPos(tooltip_pos);
     7630        SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f);
     7631        //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(
     7632        tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip;
     7633    }
     7634
     7635    char window_name[16];
     7636    ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
     7637    if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip)
     7638        if (ImGuiWindow* window = FindWindowByName(window_name))
     7639            if (window->Active)
    74447640            {
    7445                int lines_skipped = 0;
    7446                while (line < text_end && lines_skipped < lines_skippable)
    7447                {
    7448                   const char* line_end = strchr(line, '\n');
    7449                   if (!line_end)
    7450                      line_end = text_end;
    7451                   line = line_end + 1;
    7452                   lines_skipped++;
    7453                }
    7454                pos.y += lines_skipped * line_height;
     7641                // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
     7642                window->Hidden = true;
     7643                window->HiddenFramesCanSkipItems = 1;
     7644                ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
    74557645            }
    7456          }
    7457 
    7458          // Lines to render
    7459          if (line < text_end)
    7460          {
    7461             ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));
    7462             while (line < text_end)
     7646    ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize;
     7647    Begin(window_name, NULL, flags | extra_flags);
     7648}
     7649
     7650void ImGui::EndTooltip()
     7651{
     7652    IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip);   // Mismatched BeginTooltip()/EndTooltip() calls
     7653    End();
     7654}
     7655
     7656void ImGui::SetTooltipV(const char* fmt, va_list args)
     7657{
     7658    BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip);
     7659    TextV(fmt, args);
     7660    EndTooltip();
     7661}
     7662
     7663void ImGui::SetTooltip(const char* fmt, ...)
     7664{
     7665    va_list args;
     7666    va_start(args, fmt);
     7667    SetTooltipV(fmt, args);
     7668    va_end(args);
     7669}
     7670
     7671//-----------------------------------------------------------------------------
     7672// [SECTION] POPUPS
     7673//-----------------------------------------------------------------------------
     7674
     7675// Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel
     7676bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags)
     7677{
     7678    ImGuiContext& g = *GImGui;
     7679    if (popup_flags & ImGuiPopupFlags_AnyPopupId)
     7680    {
     7681        // Return true if any popup is open at the current BeginPopup() level of the popup stack
     7682        // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level.
     7683        IM_ASSERT(id == 0);
     7684        if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
     7685            return g.OpenPopupStack.Size > 0;
     7686        else
     7687            return g.OpenPopupStack.Size > g.BeginPopupStack.Size;
     7688    }
     7689    else
     7690    {
     7691        if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
     7692        {
     7693            // Return true if the popup is open anywhere in the popup stack
     7694            for (int n = 0; n < g.OpenPopupStack.Size; n++)
     7695                if (g.OpenPopupStack[n].PopupId == id)
     7696                    return true;
     7697            return false;
     7698        }
     7699        else
     7700        {
     7701            // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query)
     7702            return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
     7703        }
     7704    }
     7705}
     7706
     7707bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)
     7708{
     7709    ImGuiContext& g = *GImGui;
     7710    ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id);
     7711    if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0)
     7712        IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally
     7713    return IsPopupOpen(id, popup_flags);
     7714}
     7715
     7716ImGuiWindow* ImGui::GetTopMostPopupModal()
     7717{
     7718    ImGuiContext& g = *GImGui;
     7719    for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
     7720        if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
     7721            if (popup->Flags & ImGuiWindowFlags_Modal)
     7722                return popup;
     7723    return NULL;
     7724}
     7725
     7726void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
     7727{
     7728    ImGuiContext& g = *GImGui;
     7729    OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags);
     7730}
     7731
     7732// Mark popup as open (toggle toward open state).
     7733// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
     7734// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
     7735// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
     7736void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
     7737{
     7738    ImGuiContext& g = *GImGui;
     7739    ImGuiWindow* parent_window = g.CurrentWindow;
     7740    const int current_stack_size = g.BeginPopupStack.Size;
     7741
     7742    if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup)
     7743        if (IsPopupOpen(0u, ImGuiPopupFlags_AnyPopupId))
     7744            return;
     7745
     7746    ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
     7747    popup_ref.PopupId = id;
     7748    popup_ref.Window = NULL;
     7749    popup_ref.SourceWindow = g.NavWindow;
     7750    popup_ref.OpenFrameCount = g.FrameCount;
     7751    popup_ref.OpenParentId = parent_window->IDStack.back();
     7752    popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
     7753    popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
     7754
     7755    IMGUI_DEBUG_LOG_POPUP("OpenPopupEx(0x%08X)\n", id);
     7756    if (g.OpenPopupStack.Size < current_stack_size + 1)
     7757    {
     7758        g.OpenPopupStack.push_back(popup_ref);
     7759    }
     7760    else
     7761    {
     7762        // 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
     7763        // 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
     7764        // 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.
     7765        if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
     7766        {
     7767            g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
     7768        }
     7769        else
     7770        {
     7771            // Close child popups if any, then flag popup for open/reopen
     7772            ClosePopupToLevel(current_stack_size, false);
     7773            g.OpenPopupStack.push_back(popup_ref);
     7774        }
     7775
     7776        // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
     7777        // This is equivalent to what ClosePopupToLevel() does.
     7778        //if (g.OpenPopupStack[current_stack_size].PopupId == id)
     7779        //    FocusWindow(parent_window);
     7780    }
     7781}
     7782
     7783// When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
     7784// This function closes any popups that are over 'ref_window'.
     7785void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
     7786{
     7787    ImGuiContext& g = *GImGui;
     7788    if (g.OpenPopupStack.Size == 0)
     7789        return;
     7790
     7791    // Don't close our own child popup windows.
     7792    int popup_count_to_keep = 0;
     7793    if (ref_window)
     7794    {
     7795        // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
     7796        for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
     7797        {
     7798            ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep];
     7799            if (!popup.Window)
     7800                continue;
     7801            IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
     7802            if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
     7803                continue;
     7804
     7805            // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow)
     7806            // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3:
     7807            //     Window -> Popup1 -> Popup2 -> Popup3
     7808            // - Each popups may contain child windows, which is why we compare ->RootWindow!
     7809            //     Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child
     7810            bool ref_window_is_descendent_of_popup = false;
     7811            for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
     7812                if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
     7813                    if (popup_window->RootWindow == ref_window->RootWindow)
     7814                    {
     7815                        ref_window_is_descendent_of_popup = true;
     7816                        break;
     7817                    }
     7818            if (!ref_window_is_descendent_of_popup)
     7819                break;
     7820        }
     7821    }
     7822    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
     7823    {
     7824        IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
     7825        ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);
     7826    }
     7827}
     7828
     7829void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
     7830{
     7831    ImGuiContext& g = *GImGui;
     7832    IMGUI_DEBUG_LOG_POPUP("ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup);
     7833    IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
     7834
     7835    // Trim open popup stack
     7836    ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow;
     7837    ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;
     7838    g.OpenPopupStack.resize(remaining);
     7839
     7840    if (restore_focus_to_window_under_popup)
     7841    {
     7842        if (focus_window && !focus_window->WasActive && popup_window)
     7843        {
     7844            // Fallback
     7845            FocusTopMostWindowUnderOne(popup_window, NULL);
     7846        }
     7847        else
     7848        {
     7849            if (g.NavLayer == ImGuiNavLayer_Main && focus_window)
     7850                focus_window = NavRestoreLastChildNavWindow(focus_window);
     7851            FocusWindow(focus_window);
     7852        }
     7853    }
     7854}
     7855
     7856// Close the popup we have begin-ed into.
     7857void ImGui::CloseCurrentPopup()
     7858{
     7859    ImGuiContext& g = *GImGui;
     7860    int popup_idx = g.BeginPopupStack.Size - 1;
     7861    if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
     7862        return;
     7863
     7864    // Closing a menu closes its top-most parent popup (unless a modal)
     7865    while (popup_idx > 0)
     7866    {
     7867        ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
     7868        ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
     7869        bool close_parent = false;
     7870        if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
     7871            if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal))
     7872                close_parent = true;
     7873        if (!close_parent)
     7874            break;
     7875        popup_idx--;
     7876    }
     7877    IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
     7878    ClosePopupToLevel(popup_idx, true);
     7879
     7880    // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
     7881    // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
     7882    // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
     7883    if (ImGuiWindow* window = g.NavWindow)
     7884        window->DC.NavHideHighlightOneFrame = true;
     7885}
     7886
     7887// Attention! BeginPopup() adds default flags which BeginPopupEx()!
     7888bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
     7889{
     7890    ImGuiContext& g = *GImGui;
     7891    if (!IsPopupOpen(id, ImGuiPopupFlags_None))
     7892    {
     7893        g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
     7894        return false;
     7895    }
     7896
     7897    char name[20];
     7898    if (flags & ImGuiWindowFlags_ChildMenu)
     7899        ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
     7900    else
     7901        ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
     7902
     7903    flags |= ImGuiWindowFlags_Popup;
     7904    bool is_open = Begin(name, NULL, flags);
     7905    if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
     7906        EndPopup();
     7907
     7908    return is_open;
     7909}
     7910
     7911bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
     7912{
     7913    ImGuiContext& g = *GImGui;
     7914    if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
     7915    {
     7916        g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
     7917        return false;
     7918    }
     7919    flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
     7920    return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
     7921}
     7922
     7923// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
     7924// 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.
     7925bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
     7926{
     7927    ImGuiContext& g = *GImGui;
     7928    ImGuiWindow* window = g.CurrentWindow;
     7929    const ImGuiID id = window->GetID(name);
     7930    if (!IsPopupOpen(id, ImGuiPopupFlags_None))
     7931    {
     7932        g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
     7933        return false;
     7934    }
     7935
     7936    // Center modal windows by default for increased visibility
     7937    // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves)
     7938    // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
     7939    if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
     7940        SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
     7941
     7942    flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse;
     7943    const bool is_open = Begin(name, p_open, flags);
     7944    if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
     7945    {
     7946        EndPopup();
     7947        if (is_open)
     7948            ClosePopupToLevel(g.BeginPopupStack.Size, true);
     7949        return false;
     7950    }
     7951    return is_open;
     7952}
     7953
     7954void ImGui::EndPopup()
     7955{
     7956    ImGuiContext& g = *GImGui;
     7957    ImGuiWindow* window = g.CurrentWindow;
     7958    IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup);  // Mismatched BeginPopup()/EndPopup() calls
     7959    IM_ASSERT(g.BeginPopupStack.Size > 0);
     7960
     7961    // Make all menus and popups wrap around for now, may need to expose that policy.
     7962    if (g.NavWindow == window)
     7963        NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
     7964
     7965    // Child-popups don't need to be laid out
     7966    IM_ASSERT(g.WithinEndChild == false);
     7967    if (window->Flags & ImGuiWindowFlags_ChildWindow)
     7968        g.WithinEndChild = true;
     7969    End();
     7970    g.WithinEndChild = false;
     7971}
     7972
     7973// Helper to open a popup if mouse button is released over the item
     7974// - This is essentially the same as BeginPopupContextItem() but without the trailing BeginPopup()
     7975void ImGui::OpenPopupOnItemClick(const char* str_id, ImGuiPopupFlags popup_flags)
     7976{
     7977    ImGuiWindow* window = GImGui->CurrentWindow;
     7978    int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
     7979    if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
     7980    {
     7981        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!
     7982        IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
     7983        OpenPopupEx(id, popup_flags);
     7984    }
     7985}
     7986
     7987// This is a helper to handle the simplest case of associating one named popup to one given widget.
     7988// - You can pass a NULL str_id to use the identifier of the last item.
     7989// - You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
     7990// - This is essentially the same as calling OpenPopupOnItemClick() + BeginPopup() but written to avoid
     7991//   computing the ID twice because BeginPopupContextXXX functions may be called very frequently.
     7992bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
     7993{
     7994    ImGuiWindow* window = GImGui->CurrentWindow;
     7995    if (window->SkipItems)
     7996        return false;
     7997    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!
     7998    IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
     7999    int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
     8000    if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
     8001        OpenPopupEx(id, popup_flags);
     8002    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
     8003}
     8004
     8005bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
     8006{
     8007    ImGuiWindow* window = GImGui->CurrentWindow;
     8008    if (!str_id)
     8009        str_id = "window_context";
     8010    ImGuiID id = window->GetID(str_id);
     8011    int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
     8012    if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
     8013        if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())
     8014            OpenPopupEx(id, popup_flags);
     8015    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
     8016}
     8017
     8018bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
     8019{
     8020    ImGuiWindow* window = GImGui->CurrentWindow;
     8021    if (!str_id)
     8022        str_id = "void_context";
     8023    ImGuiID id = window->GetID(str_id);
     8024    int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
     8025    if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
     8026        if (GetTopMostPopupModal() == NULL)
     8027            OpenPopupEx(id, popup_flags);
     8028    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
     8029}
     8030
     8031// 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.)
     8032// 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.
     8033ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)
     8034{
     8035    ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
     8036    //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
     8037    //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
     8038
     8039    // Combo Box policy (we want a connecting edge)
     8040    if (policy == ImGuiPopupPositionPolicy_ComboBox)
     8041    {
     8042        const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };
     8043        for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
     8044        {
     8045            const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
     8046            if (n != -1 && dir == *last_dir) // Already tried this direction?
     8047                continue;
     8048            ImVec2 pos;
     8049            if (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default)
     8050            if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
     8051            if (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
     8052            if (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
     8053            if (!r_outer.Contains(ImRect(pos, pos + size)))
     8054                continue;
     8055            *last_dir = dir;
     8056            return pos;
     8057        }
     8058    }
     8059
     8060    // Tooltip and Default popup policy
     8061    // (Always first try the direction we used on the last frame, if any)
     8062    if (policy == ImGuiPopupPositionPolicy_Tooltip || policy == ImGuiPopupPositionPolicy_Default)
     8063    {
     8064        const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
     8065        for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
     8066        {
     8067            const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
     8068            if (n != -1 && dir == *last_dir) // Already tried this direction?
     8069                continue;
     8070
     8071            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);
     8072            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);
     8073
     8074            // 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)
     8075            if (avail_w < size.x && (dir == ImGuiDir_Left || dir == ImGuiDir_Right))
     8076                continue;
     8077            if (avail_h < size.y && (dir == ImGuiDir_Up || dir == ImGuiDir_Down))
     8078                continue;
     8079
     8080            ImVec2 pos;
     8081            pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
     8082            pos.y = (dir == ImGuiDir_Up) ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down) ? r_avoid.Max.y : base_pos_clamped.y;
     8083
     8084            // Clamp top-left corner of popup
     8085            pos.x = ImMax(pos.x, r_outer.Min.x);
     8086            pos.y = ImMax(pos.y, r_outer.Min.y);
     8087
     8088            *last_dir = dir;
     8089            return pos;
     8090        }
     8091    }
     8092
     8093    // Fallback when not enough room:
     8094    *last_dir = ImGuiDir_None;
     8095
     8096    // For tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
     8097    if (policy == ImGuiPopupPositionPolicy_Tooltip)
     8098        return ref_pos + ImVec2(2, 2);
     8099
     8100    // Otherwise try to keep within display
     8101    ImVec2 pos = ref_pos;
     8102    pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
     8103    pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
     8104    return pos;
     8105}
     8106
     8107ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
     8108{
     8109    IM_UNUSED(window);
     8110    ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding;
     8111    ImRect r_screen = GetViewportRect();
     8112    r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
     8113    return r_screen;
     8114}
     8115
     8116ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
     8117{
     8118    ImGuiContext& g = *GImGui;
     8119
     8120    ImRect r_outer = GetWindowAllowedExtentRect(window);
     8121    if (window->Flags & ImGuiWindowFlags_ChildMenu)
     8122    {
     8123        // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
     8124        // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
     8125        IM_ASSERT(g.CurrentWindow == window);
     8126        ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
     8127        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).
     8128        ImRect r_avoid;
     8129        if (parent_window->DC.MenuBarAppending)
     8130            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
     8131        else
     8132            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);
     8133        return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
     8134    }
     8135    if (window->Flags & ImGuiWindowFlags_Popup)
     8136    {
     8137        ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
     8138        return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Default);
     8139    }
     8140    if (window->Flags & ImGuiWindowFlags_Tooltip)
     8141    {
     8142        // Position tooltip (always follows mouse)
     8143        float sc = g.Style.MouseCursorScale;
     8144        ImVec2 ref_pos = NavCalcPreferredRefPos();
     8145        ImRect r_avoid;
     8146        if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))
     8147            r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
     8148        else
     8149            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.
     8150        return FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip);
     8151    }
     8152    IM_ASSERT(0);
     8153    return window->Pos;
     8154}
     8155
     8156//-----------------------------------------------------------------------------
     8157// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
     8158//-----------------------------------------------------------------------------
     8159
     8160// FIXME-NAV: The existence of SetNavID vs SetNavIDWithRectRel vs SetFocusID is incredibly messy and confusing,
     8161// and needs some explanation or serious refactoring.
     8162void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id)
     8163{
     8164    ImGuiContext& g = *GImGui;
     8165    IM_ASSERT(g.NavWindow);
     8166    IM_ASSERT(nav_layer == 0 || nav_layer == 1);
     8167    g.NavId = id;
     8168    g.NavFocusScopeId = focus_scope_id;
     8169    g.NavWindow->NavLastIds[nav_layer] = id;
     8170}
     8171
     8172void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
     8173{
     8174    ImGuiContext& g = *GImGui;
     8175    SetNavID(id, nav_layer, focus_scope_id);
     8176    g.NavWindow->NavRectRel[nav_layer] = rect_rel;
     8177    g.NavMousePosDirty = true;
     8178    g.NavDisableHighlight = false;
     8179    g.NavDisableMouseHover = true;
     8180}
     8181
     8182void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
     8183{
     8184    ImGuiContext& g = *GImGui;
     8185    IM_ASSERT(id != 0);
     8186
     8187    // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid.
     8188    // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)
     8189    const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
     8190    if (g.NavWindow != window)
     8191        g.NavInitRequest = false;
     8192    g.NavWindow = window;
     8193    g.NavId = id;
     8194    g.NavLayer = nav_layer;
     8195    g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
     8196    window->NavLastIds[nav_layer] = id;
     8197    if (window->DC.LastItemId == id)
     8198        window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
     8199
     8200    if (g.ActiveIdSource == ImGuiInputSource_Nav)
     8201        g.NavDisableMouseHover = true;
     8202    else
     8203        g.NavDisableHighlight = true;
     8204}
     8205
     8206ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
     8207{
     8208    if (ImFabs(dx) > ImFabs(dy))
     8209        return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
     8210    return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
     8211}
     8212
     8213static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
     8214{
     8215    if (a1 < b0)
     8216        return a1 - b0;
     8217    if (b1 < a0)
     8218        return a0 - b1;
     8219    return 0.0f;
     8220}
     8221
     8222static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
     8223{
     8224    if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
     8225    {
     8226        r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
     8227        r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
     8228    }
     8229    else
     8230    {
     8231        r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
     8232        r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
     8233    }
     8234}
     8235
     8236// Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
     8237static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
     8238{
     8239    ImGuiContext& g = *GImGui;
     8240    ImGuiWindow* window = g.CurrentWindow;
     8241    if (g.NavLayer != window->DC.NavLayerCurrent)
     8242        return false;
     8243
     8244    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)
     8245    g.NavScoringCount++;
     8246
     8247    // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
     8248    if (window->ParentWindow == g.NavWindow)
     8249    {
     8250        IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
     8251        if (!window->ClipRect.Overlaps(cand))
     8252            return false;
     8253        cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
     8254    }
     8255
     8256    // 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)
     8257    // For example, this ensure that items in one column are not reached when moving vertically from items in another column.
     8258    NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect);
     8259
     8260    // Compute distance between boxes
     8261    // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
     8262    float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
     8263    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
     8264    if (dby != 0.0f && dbx != 0.0f)
     8265        dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
     8266    float dist_box = ImFabs(dbx) + ImFabs(dby);
     8267
     8268    // 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)
     8269    float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
     8270    float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
     8271    float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
     8272
     8273    // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
     8274    ImGuiDir quadrant;
     8275    float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
     8276    if (dbx != 0.0f || dby != 0.0f)
     8277    {
     8278        // For non-overlapping boxes, use distance between boxes
     8279        dax = dbx;
     8280        day = dby;
     8281        dist_axial = dist_box;
     8282        quadrant = ImGetDirQuadrantFromDelta(dbx, dby);
     8283    }
     8284    else if (dcx != 0.0f || dcy != 0.0f)
     8285    {
     8286        // For overlapping boxes with different centers, use distance between centers
     8287        dax = dcx;
     8288        day = dcy;
     8289        dist_axial = dist_center;
     8290        quadrant = ImGetDirQuadrantFromDelta(dcx, dcy);
     8291    }
     8292    else
     8293    {
     8294        // 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)
     8295        quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
     8296    }
     8297
     8298#if IMGUI_DEBUG_NAV_SCORING
     8299    char buf[128];
     8300    if (IsMouseHoveringRect(cand.Min, cand.Max))
     8301    {
     8302        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]);
     8303        ImDrawList* draw_list = GetForegroundDrawList(window);
     8304        draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
     8305        draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
     8306        draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150));
     8307        draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
     8308    }
     8309    else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
     8310    {
     8311        if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
     8312        if (quadrant == g.NavMoveDir)
     8313        {
     8314            ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
     8315            ImDrawList* draw_list = GetForegroundDrawList(window);
     8316            draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
     8317            draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
     8318        }
     8319    }
     8320#endif
     8321
     8322    // Is it in the quadrant we're interesting in moving to?
     8323    bool new_best = false;
     8324    if (quadrant == g.NavMoveDir)
     8325    {
     8326        // Does it beat the current best candidate?
     8327        if (dist_box < result->DistBox)
     8328        {
     8329            result->DistBox = dist_box;
     8330            result->DistCenter = dist_center;
     8331            return true;
     8332        }
     8333        if (dist_box == result->DistBox)
     8334        {
     8335            // Try using distance between center points to break ties
     8336            if (dist_center < result->DistCenter)
    74638337            {
    7464                const char* line_end = strchr(line, '\n');
    7465                if (IsClippedEx(line_rect, 0, false))
    7466                   break;
    7467 
    7468                const ImVec2 line_size = CalcTextSize(line, line_end, false);
    7469                text_size.x = ImMax(text_size.x, line_size.x);
    7470                RenderText(pos, line, line_end, false);
    7471                if (!line_end)
    7472                   line_end = text_end;
    7473                line = line_end + 1;
    7474                line_rect.Min.y += line_height;
    7475                line_rect.Max.y += line_height;
    7476                pos.y += line_height;
     8338                result->DistCenter = dist_center;
     8339                new_best = true;
    74778340            }
    7478 
    7479             // Count remaining lines
    7480             int lines_skipped = 0;
    7481             while (line < text_end)
     8341            else if (dist_center == result->DistCenter)
    74828342            {
    7483                const char* line_end = strchr(line, '\n');
    7484                if (!line_end)
    7485                   line_end = text_end;
    7486                line = line_end + 1;
    7487                lines_skipped++;
     8343                // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
     8344                // (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),
     8345                // 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.
     8346                if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
     8347                    new_best = true;
    74888348            }
    7489             pos.y += lines_skipped * line_height;
    7490          }
    7491 
    7492          text_size.y += (pos - text_pos).y;
    7493       }
    7494 
    7495       ImRect bb(text_pos, text_pos + text_size);
    7496       ItemSize(bb);
    7497       ItemAdd(bb, 0);
    7498    }
    7499    else
    7500    {
    7501       const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;
    7502       const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
    7503 
    7504       // Account of baseline offset
    7505       ImRect bb(text_pos, text_pos + text_size);
    7506       ItemSize(text_size);
    7507       if (!ItemAdd(bb, 0))
    7508          return;
    7509 
    7510       // Render (we don't hide text after ## in this end-user function)
    7511       RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width);
    7512    }
    7513 }
    7514 
    7515 void ImGui::AlignTextToFramePadding()
    7516 {
    7517    ImGuiWindow* window = GetCurrentWindow();
    7518    if (window->SkipItems)
    7519       return;
    7520 
    7521    ImGuiContext& g = *GImGui;
    7522    window->DC.CurrentLineHeight = ImMax(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y * 2);
    7523    window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y);
    7524 }
    7525 
    7526 // Add a label+text combo aligned to other label+value widgets
    7527 void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
    7528 {
    7529    ImGuiWindow* window = GetCurrentWindow();
    7530    if (window->SkipItems)
    7531       return;
    7532 
    7533    ImGuiContext& g = *GImGui;
    7534    const ImGuiStyle& style = g.Style;
    7535    const float w = CalcItemWidth();
    7536 
    7537    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    7538    const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2));
    7539    const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y * 2) + label_size);
    7540    ItemSize(total_bb, style.FramePadding.y);
    7541    if (!ItemAdd(total_bb, 0))
    7542       return;
    7543 
    7544    // Render
    7545    const char* value_text_begin = &g.TempBuffer[0];
    7546    const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
    7547    RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f, 0.5f));
    7548    if (label_size.x > 0.0f)
    7549       RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);
    7550 }
    7551 
    7552 void ImGui::LabelText(const char* label, const char* fmt, ...)
    7553 {
    7554    va_list args;
    7555    va_start(args, fmt);
    7556    LabelTextV(label, fmt, args);
    7557    va_end(args);
    7558 }
    7559 
    7560 bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags)
    7561 {
    7562    ImGuiContext& g = *GImGui;
    7563    ImGuiWindow* window = GetCurrentWindow();
    7564 
    7565    if (flags & ImGuiButtonFlags_Disabled)
    7566    {
    7567       if (out_hovered) *out_hovered = false;
    7568       if (out_held) *out_held = false;
    7569       if (g.ActiveId == id) ClearActiveID();
    7570       return false;
    7571    }
    7572 
    7573    // Default behavior requires click+release on same spot
    7574    if ((flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick)) == 0)
    7575       flags |= ImGuiButtonFlags_PressedOnClickRelease;
    7576 
    7577    ImGuiWindow* backup_hovered_window = g.HoveredWindow;
    7578    if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
    7579       g.HoveredWindow = window;
    7580 
    7581    bool pressed = false;
    7582    bool hovered = ItemHoverable(bb, id);
    7583 
    7584    // Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button
    7585    if ((flags & ImGuiButtonFlags_PressedOnDragDropHold) && g.DragDropActive && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
    7586       if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
    7587       {
    7588          hovered = true;
    7589          SetHoveredID(id);
    7590          if (CalcTypematicPressedRepeatAmount(g.HoveredIdTimer + 0.0001f, g.HoveredIdTimer + 0.0001f - g.IO.DeltaTime, 0.01f, 0.70f)) // FIXME: Our formula for CalcTypematicPressedRepeatAmount() is fishy
    7591          {
    7592             pressed = true;
    7593             FocusWindow(window);
    7594          }
    7595       }
    7596 
    7597    if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
    7598       g.HoveredWindow = backup_hovered_window;
    7599 
    7600    // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one.
    7601    if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0))
    7602       hovered = false;
    7603 
    7604    // Mouse
    7605    if (hovered)
    7606    {
    7607       if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt))
    7608       {
    7609          //                        | CLICKING        | HOLDING with ImGuiButtonFlags_Repeat
    7610          // PressedOnClickRelease  |  <on release>*  |  <on repeat> <on repeat> .. (NOT on release)  <-- MOST COMMON! (*) only if both click/release were over bounds
    7611          // PressedOnClick         |  <on click>     |  <on click> <on repeat> <on repeat> ..
    7612          // PressedOnRelease       |  <on release>   |  <on repeat> <on repeat> .. (NOT on release)
    7613          // PressedOnDoubleClick   |  <on dclick>    |  <on dclick> <on repeat> <on repeat> ..
    7614          // FIXME-NAV: We don't honor those different behaviors.
    7615          if ((flags & ImGuiButtonFlags_PressedOnClickRelease) && g.IO.MouseClicked[0])
    7616          {
    7617             SetActiveID(id, window);
    7618             if (!(flags & ImGuiButtonFlags_NoNavFocus))
    7619                SetFocusID(id, window);
    7620             FocusWindow(window);
    7621          }
    7622          if (((flags & ImGuiButtonFlags_PressedOnClick) && g.IO.MouseClicked[0]) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseDoubleClicked[0]))
    7623          {
    7624             pressed = true;
    7625             if (flags & ImGuiButtonFlags_NoHoldingActiveID)
    7626                ClearActiveID();
    7627             else
    7628                SetActiveID(id, window); // Hold on ID
    7629             FocusWindow(window);
    7630          }
    7631          if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0])
    7632          {
    7633             if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay))  // Repeat mode trumps <on release>
    7634                pressed = true;
    7635             ClearActiveID();
    7636          }
    7637 
    7638          // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above).
    7639          // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings.
    7640          if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true))
    7641             pressed = true;
    7642       }
    7643 
    7644       if (pressed)
    7645          g.NavDisableHighlight = true;
    7646    }
    7647 
    7648    // Gamepad/Keyboard navigation
    7649    // We report navigated item as hovered but we don't set g.HoveredId to not interfere with mouse.
    7650    if (g.NavId == id && !g.NavDisableHighlight && g.NavDisableMouseHover && (g.ActiveId == 0 || g.ActiveId == id || g.ActiveId == window->MoveId))
    7651       hovered = true;
    7652 
    7653    if (g.NavActivateDownId == id)
    7654    {
    7655       bool nav_activated_by_code = (g.NavActivateId == id);
    7656       bool nav_activated_by_inputs = IsNavInputPressed(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiInputReadMode_Repeat : ImGuiInputReadMode_Pressed);
    7657       if (nav_activated_by_code || nav_activated_by_inputs)
    7658          pressed = true;
    7659       if (nav_activated_by_code || nav_activated_by_inputs || g.ActiveId == id)
    7660       {
    7661          // Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.
    7662          g.NavActivateId = id; // This is so SetActiveId assign a Nav source
    7663          SetActiveID(id, window);
    7664          if (!(flags & ImGuiButtonFlags_NoNavFocus))
    7665             SetFocusID(id, window);
    7666          g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
    7667       }
    7668    }
    7669 
    7670    bool held = false;
    7671    if (g.ActiveId == id)
    7672    {
    7673       if (g.ActiveIdSource == ImGuiInputSource_Mouse)
    7674       {
    7675          if (g.ActiveIdIsJustActivated)
    7676             g.ActiveIdClickOffset = g.IO.MousePos - bb.Min;
    7677          if (g.IO.MouseDown[0])
    7678          {
    7679             held = true;
    7680          }
    7681          else
    7682          {
    7683             if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease))
    7684                if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay))  // Repeat mode trumps <on release>
    7685                   if (!g.DragDropActive)
    7686                      pressed = true;
    7687             ClearActiveID();
    7688          }
    7689          if (!(flags & ImGuiButtonFlags_NoNavFocus))
    7690             g.NavDisableHighlight = true;
    7691       }
    7692       else if (g.ActiveIdSource == ImGuiInputSource_Nav)
    7693       {
    7694          if (g.NavActivateDownId != id)
    7695             ClearActiveID();
    7696       }
    7697    }
    7698 
    7699    if (out_hovered) *out_hovered = hovered;
    7700    if (out_held) *out_held = held;
    7701 
    7702    return pressed;
    7703 }
    7704 
    7705 bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags)
    7706 {
    7707    ImGuiWindow* window = GetCurrentWindow();
    7708    if (window->SkipItems)
    7709       return false;
    7710 
    7711    ImGuiContext& g = *GImGui;
    7712    const ImGuiStyle& style = g.Style;
    7713    const ImGuiID id = window->GetID(label);
    7714    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    7715 
    7716    ImVec2 pos = window->DC.CursorPos;
    7717    if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
    7718       pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
    7719    ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
    7720 
    7721    const ImRect bb(pos, pos + size);
    7722    ItemSize(bb, style.FramePadding.y);
    7723    if (!ItemAdd(bb, id))
    7724       return false;
    7725 
    7726    if (window->DC.ItemFlags & ImGuiItemFlags_ButtonRepeat)
    7727       flags |= ImGuiButtonFlags_Repeat;
    7728    bool hovered, held;
    7729    bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
    7730 
    7731    // Render
    7732    const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
    7733    RenderNavHighlight(bb, id);
    7734    RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
    7735    RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
    7736 
    7737    // Automatically close popups
    7738    //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
    7739    //    CloseCurrentPopup();
    7740 
    7741    return pressed;
    7742 }
    7743 
    7744 bool ImGui::Button(const char* label, const ImVec2& size_arg)
    7745 {
    7746    return ButtonEx(label, size_arg, 0);
    7747 }
    7748 
    7749 // Small buttons fits within text without additional vertical spacing.
    7750 bool ImGui::SmallButton(const char* label)
    7751 {
    7752    ImGuiContext& g = *GImGui;
    7753    float backup_padding_y = g.Style.FramePadding.y;
    7754    g.Style.FramePadding.y = 0.0f;
    7755    bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine);
    7756    g.Style.FramePadding.y = backup_padding_y;
    7757    return pressed;
    7758 }
    7759 
    7760 bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir)
    7761 {
    7762    ImGuiWindow* window = GetCurrentWindow();
    7763    if (window->SkipItems)
    7764       return false;
    7765 
    7766    ImGuiContext& g = *GImGui;
    7767    const ImGuiID id = window->GetID(str_id);
    7768    float sz = ImGui::GetFrameHeight();
    7769    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(sz, sz));
    7770    ItemSize(bb);
    7771    if (!ItemAdd(bb, id))
    7772       return false;
    7773 
    7774    bool hovered, held;
    7775    bool pressed = ButtonBehavior(bb, id, &hovered, &held);
    7776 
    7777    // Render
    7778    const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
    7779    RenderNavHighlight(bb, id);
    7780    RenderFrame(bb.Min, bb.Max, col, true, g.Style.FrameRounding);
    7781    RenderArrow(bb.Min + g.Style.FramePadding, dir);
    7782 
    7783    return pressed;
    7784 }
    7785 
    7786 // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack.
    7787 // Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id)
    7788 bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg)
    7789 {
    7790    ImGuiWindow* window = GetCurrentWindow();
    7791    if (window->SkipItems)
    7792       return false;
    7793 
    7794    const ImGuiID id = window->GetID(str_id);
    7795    ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);
    7796    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
    7797    ItemSize(bb);
    7798    if (!ItemAdd(bb, id))
    7799       return false;
    7800 
    7801    bool hovered, held;
    7802    bool pressed = ButtonBehavior(bb, id, &hovered, &held);
    7803 
    7804    return pressed;
    7805 }
    7806 
    7807 // Button to close a window
    7808 bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
    7809 {
    7810    ImGuiContext& g = *GImGui;
    7811    ImGuiWindow* window = g.CurrentWindow;
    7812 
    7813    // We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window.
    7814    // (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible).
    7815    const ImRect bb(pos - ImVec2(radius, radius), pos + ImVec2(radius, radius));
    7816    bool is_clipped = !ItemAdd(bb, id);
    7817 
    7818    bool hovered, held;
    7819    bool pressed = ButtonBehavior(bb, id, &hovered, &held);
    7820    if (is_clipped)
    7821       return pressed;
    7822 
    7823    // Render
    7824    ImVec2 center = bb.GetCenter();
    7825    if (hovered)
    7826       window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9);
    7827 
    7828    float cross_extent = (radius * 0.7071f) - 1.0f;
    7829    ImU32 cross_col = GetColorU32(ImGuiCol_Text);
    7830    center -= ImVec2(0.5f, 0.5f);
    7831    window->DrawList->AddLine(center + ImVec2(+cross_extent, +cross_extent), center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f);
    7832    window->DrawList->AddLine(center + ImVec2(+cross_extent, -cross_extent), center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f);
    7833 
    7834    return pressed;
    7835 }
    7836 
    7837 void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
    7838 {
    7839    ImGuiWindow* window = GetCurrentWindow();
    7840    if (window->SkipItems)
    7841       return;
    7842 
    7843    ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
    7844    if (border_col.w > 0.0f)
    7845       bb.Max += ImVec2(2, 2);
    7846    ItemSize(bb);
    7847    if (!ItemAdd(bb, 0))
    7848       return;
    7849 
    7850    if (border_col.w > 0.0f)
    7851    {
    7852       window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f);
    7853       window->DrawList->AddImage(user_texture_id, bb.Min + ImVec2(1, 1), bb.Max - ImVec2(1, 1), uv0, uv1, GetColorU32(tint_col));
    7854    }
    7855    else
    7856    {
    7857       window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col));
    7858    }
    7859 }
    7860 
    7861 // frame_padding < 0: uses FramePadding from style (default)
    7862 // frame_padding = 0: no framing
    7863 // frame_padding > 0: set framing size
    7864 // The color used are the button colors.
    7865 bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)
    7866 {
    7867    ImGuiWindow* window = GetCurrentWindow();
    7868    if (window->SkipItems)
    7869       return false;
    7870 
    7871    ImGuiContext& g = *GImGui;
    7872    const ImGuiStyle& style = g.Style;
    7873 
    7874    // Default to using texture ID as ID. User can still push string/integer prefixes.
    7875    // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV.
    7876    PushID((void *)user_texture_id);
    7877    const ImGuiID id = window->GetID("#image");
    7878    PopID();
    7879 
    7880    const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding;
    7881    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2);
    7882    const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size);
    7883    ItemSize(bb);
    7884    if (!ItemAdd(bb, id))
    7885       return false;
    7886 
    7887    bool hovered, held;
    7888    bool pressed = ButtonBehavior(bb, id, &hovered, &held);
    7889 
    7890    // Render
    7891    const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
    7892    RenderNavHighlight(bb, id);
    7893    RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding));
    7894    if (bg_col.w > 0.0f)
    7895       window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col));
    7896    window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col));
    7897 
    7898    return pressed;
    7899 }
    7900 
    7901 // Start logging ImGui output to TTY
    7902 void ImGui::LogToTTY(int max_depth)
    7903 {
    7904    ImGuiContext& g = *GImGui;
    7905    if (g.LogEnabled)
    7906       return;
    7907    ImGuiWindow* window = g.CurrentWindow;
    7908 
    7909    IM_ASSERT(g.LogFile == NULL);
    7910    g.LogFile = stdout;
    7911    g.LogEnabled = true;
    7912    g.LogStartDepth = window->DC.TreeDepth;
    7913    if (max_depth >= 0)
    7914       g.LogAutoExpandMaxDepth = max_depth;
    7915 }
    7916 
    7917 // Start logging ImGui output to given file
    7918 void ImGui::LogToFile(int max_depth, const char* filename)
    7919 {
    7920    ImGuiContext& g = *GImGui;
    7921    if (g.LogEnabled)
    7922       return;
    7923    ImGuiWindow* window = g.CurrentWindow;
    7924 
    7925    if (!filename)
    7926    {
    7927       filename = g.IO.LogFilename;
    7928       if (!filename)
    7929          return;
    7930    }
    7931 
    7932    IM_ASSERT(g.LogFile == NULL);
    7933    g.LogFile = ImFileOpen(filename, "ab");
    7934    if (!g.LogFile)
    7935    {
    7936       IM_ASSERT(g.LogFile != NULL); // Consider this an error
    7937       return;
    7938    }
    7939    g.LogEnabled = true;
    7940    g.LogStartDepth = window->DC.TreeDepth;
    7941    if (max_depth >= 0)
    7942       g.LogAutoExpandMaxDepth = max_depth;
    7943 }
    7944 
    7945 // Start logging ImGui output to clipboard
    7946 void ImGui::LogToClipboard(int max_depth)
    7947 {
    7948    ImGuiContext& g = *GImGui;
    7949    if (g.LogEnabled)
    7950       return;
    7951    ImGuiWindow* window = g.CurrentWindow;
    7952 
    7953    IM_ASSERT(g.LogFile == NULL);
    7954    g.LogFile = NULL;
    7955    g.LogEnabled = true;
    7956    g.LogStartDepth = window->DC.TreeDepth;
    7957    if (max_depth >= 0)
    7958       g.LogAutoExpandMaxDepth = max_depth;
    7959 }
    7960 
    7961 void ImGui::LogFinish()
    7962 {
    7963    ImGuiContext& g = *GImGui;
    7964    if (!g.LogEnabled)
    7965       return;
    7966 
    7967    LogText(IM_NEWLINE);
    7968    if (g.LogFile != NULL)
    7969    {
    7970       if (g.LogFile == stdout)
    7971          fflush(g.LogFile);
    7972       else
    7973          fclose(g.LogFile);
    7974       g.LogFile = NULL;
    7975    }
    7976    if (g.LogClipboard->size() > 1)
    7977    {
    7978       SetClipboardText(g.LogClipboard->begin());
    7979       g.LogClipboard->clear();
    7980    }
    7981    g.LogEnabled = false;
    7982 }
    7983 
    7984 // Helper to display logging buttons
    7985 void ImGui::LogButtons()
    7986 {
    7987    ImGuiContext& g = *GImGui;
    7988 
    7989    PushID("LogButtons");
    7990    const bool log_to_tty = Button("Log To TTY"); SameLine();
    7991    const bool log_to_file = Button("Log To File"); SameLine();
    7992    const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
    7993    PushItemWidth(80.0f);
    7994    PushAllowKeyboardFocus(false);
    7995    SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL);
    7996    PopAllowKeyboardFocus();
    7997    PopItemWidth();
    7998    PopID();
    7999 
    8000    // Start logging at the end of the function so that the buttons don't appear in the log
    8001    if (log_to_tty)
    8002       LogToTTY(g.LogAutoExpandMaxDepth);
    8003    if (log_to_file)
    8004       LogToFile(g.LogAutoExpandMaxDepth, g.IO.LogFilename);
    8005    if (log_to_clipboard)
    8006       LogToClipboard(g.LogAutoExpandMaxDepth);
    8007 }
    8008 
    8009 bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
    8010 {
    8011    if (flags & ImGuiTreeNodeFlags_Leaf)
    8012       return true;
    8013 
    8014    // We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions)
    8015    ImGuiContext& g = *GImGui;
    8016    ImGuiWindow* window = g.CurrentWindow;
    8017    ImGuiStorage* storage = window->DC.StateStorage;
    8018 
    8019    bool is_open;
    8020    if (g.NextTreeNodeOpenCond != 0)
    8021    {
    8022       if (g.NextTreeNodeOpenCond & ImGuiCond_Always)
    8023       {
    8024          is_open = g.NextTreeNodeOpenVal;
    8025          storage->SetInt(id, is_open);
    8026       }
    8027       else
    8028       {
    8029          // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently.
    8030          const int stored_value = storage->GetInt(id, -1);
    8031          if (stored_value == -1)
    8032          {
    8033             is_open = g.NextTreeNodeOpenVal;
    8034             storage->SetInt(id, is_open);
    8035          }
    8036          else
    8037          {
    8038             is_open = stored_value != 0;
    8039          }
    8040       }
    8041       g.NextTreeNodeOpenCond = 0;
    8042    }
    8043    else
    8044    {
    8045       is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;
    8046    }
    8047 
    8048    // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior).
    8049    // NB- If we are above max depth we still allow manually opened nodes to be logged.
    8050    if (g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && window->DC.TreeDepth < g.LogAutoExpandMaxDepth)
    8051       is_open = true;
    8052 
    8053    return is_open;
    8054 }
    8055 
    8056 bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
    8057 {
    8058    ImGuiWindow* window = GetCurrentWindow();
    8059    if (window->SkipItems)
    8060       return false;
    8061 
    8062    ImGuiContext& g = *GImGui;
    8063    const ImGuiStyle& style = g.Style;
    8064    const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
    8065    const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f);
    8066 
    8067    if (!label_end)
    8068       label_end = FindRenderedTextEnd(label);
    8069    const ImVec2 label_size = CalcTextSize(label, label_end, false);
    8070 
    8071    // We vertically grow up to current line height up the typical widget height.
    8072    const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
    8073    const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2);
    8074    ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height));
    8075    if (display_frame)
    8076    {
    8077       // Framed header expand a little outside the default padding
    8078       frame_bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1;
    8079       frame_bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1;
    8080    }
    8081 
    8082    const float text_offset_x = (g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2));   // Collapser arrow width + Spacing
    8083    const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f);   // Include collapser
    8084    ItemSize(ImVec2(text_width, frame_height), text_base_offset_y);
    8085 
    8086    // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
    8087    // (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not)
    8088    const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x * 2, frame_bb.Max.y);
    8089    bool is_open = TreeNodeBehaviorIsOpen(id, flags);
    8090 
    8091    // Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child.
    8092    // For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
    8093    // This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero.
    8094    if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
    8095       window->DC.TreeDepthMayJumpToParentOnPop |= (1 << window->DC.TreeDepth);
    8096 
    8097    bool item_add = ItemAdd(interact_bb, id);
    8098    window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
    8099    window->DC.LastItemDisplayRect = frame_bb;
    8100 
    8101    if (!item_add)
    8102    {
    8103       if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
    8104          TreePushRawID(id);
    8105       return is_open;
    8106    }
    8107 
    8108    // Flags that affects opening behavior:
    8109    // - 0(default) ..................... single-click anywhere to open
    8110    // - OpenOnDoubleClick .............. double-click anywhere to open
    8111    // - OpenOnArrow .................... single-click on arrow to open
    8112    // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
    8113    ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers | ((flags & ImGuiTreeNodeFlags_AllowItemOverlap) ? ImGuiButtonFlags_AllowItemOverlap : 0);
    8114    if (!(flags & ImGuiTreeNodeFlags_Leaf))
    8115       button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
    8116    if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
    8117       button_flags |= ImGuiButtonFlags_PressedOnDoubleClick | ((flags & ImGuiTreeNodeFlags_OpenOnArrow) ? ImGuiButtonFlags_PressedOnClickRelease : 0);
    8118 
    8119    bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
    8120    if (!(flags & ImGuiTreeNodeFlags_Leaf))
    8121    {
    8122       bool toggled = false;
    8123       if (pressed)
    8124       {
    8125          toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id);
    8126          if (flags & ImGuiTreeNodeFlags_OpenOnArrow)
    8127             toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y)) && (!g.NavDisableMouseHover);
    8128          if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
    8129             toggled |= g.IO.MouseDoubleClicked[0];
    8130          if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.
    8131             toggled = false;
    8132       }
    8133 
    8134       if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Left && is_open)
    8135       {
    8136          toggled = true;
    8137          NavMoveRequestCancel();
    8138       }
    8139       if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
    8140       {
    8141          toggled = true;
    8142          NavMoveRequestCancel();
    8143       }
    8144 
    8145       if (toggled)
    8146       {
    8147          is_open = !is_open;
    8148          window->DC.StateStorage->SetInt(id, is_open);
    8149       }
    8150    }
    8151    if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
    8152       SetItemAllowOverlap();
    8153 
    8154    // Render
    8155    const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
    8156    const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y);
    8157    if (display_frame)
    8158    {
    8159       // Framed type
    8160       RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding);
    8161       RenderNavHighlight(frame_bb, id, ImGuiNavHighlightFlags_TypeThin);
    8162       RenderArrow(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
    8163       if (g.LogEnabled)
    8164       {
    8165          // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here.
    8166          const char log_prefix[] = "\n##";
    8167          const char log_suffix[] = "##";
    8168          LogRenderedText(&text_pos, log_prefix, log_prefix + 3);
    8169          RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
    8170          LogRenderedText(&text_pos, log_suffix + 1, log_suffix + 3);
    8171       }
    8172       else
    8173       {
    8174          RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
    8175       }
    8176    }
    8177    else
    8178    {
    8179       // Unframed typed for tree nodes
    8180       if (hovered || (flags & ImGuiTreeNodeFlags_Selected))
    8181       {
    8182          RenderFrame(frame_bb.Min, frame_bb.Max, col, false);
    8183          RenderNavHighlight(frame_bb, id, ImGuiNavHighlightFlags_TypeThin);
    8184       }
    8185 
    8186       if (flags & ImGuiTreeNodeFlags_Bullet)
    8187          RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y));
    8188       else if (!(flags & ImGuiTreeNodeFlags_Leaf))
    8189          RenderArrow(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
    8190       if (g.LogEnabled)
    8191          LogRenderedText(&text_pos, ">");
    8192       RenderText(text_pos, label, label_end, false);
    8193    }
    8194 
    8195    if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
    8196       TreePushRawID(id);
    8197    return is_open;
    8198 }
    8199 
    8200 // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag).
    8201 // This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode().
    8202 bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags)
    8203 {
    8204    ImGuiWindow* window = GetCurrentWindow();
    8205    if (window->SkipItems)
    8206       return false;
    8207 
    8208    return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen, label);
    8209 }
    8210 
    8211 bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags)
    8212 {
    8213    ImGuiWindow* window = GetCurrentWindow();
    8214    if (window->SkipItems)
    8215       return false;
    8216 
    8217    if (p_open && !*p_open)
    8218       return false;
    8219 
    8220    ImGuiID id = window->GetID(label);
    8221    bool is_open = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap : 0), label);
    8222    if (p_open)
    8223    {
    8224       // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
    8225       ImGuiContext& g = *GImGui;
    8226       float button_sz = g.FontSize * 0.5f;
    8227       ImGuiItemHoveredDataBackup last_item_backup;
    8228       if (CloseButton(window->GetID((void*)(intptr_t)(id + 1)), ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz))
    8229          *p_open = false;
    8230       last_item_backup.Restore();
    8231    }
    8232 
    8233    return is_open;
    8234 }
    8235 
    8236 bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags)
    8237 {
    8238    ImGuiWindow* window = GetCurrentWindow();
    8239    if (window->SkipItems)
    8240       return false;
    8241 
    8242    return TreeNodeBehavior(window->GetID(label), flags, label, NULL);
    8243 }
    8244 
    8245 bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
    8246 {
    8247    ImGuiWindow* window = GetCurrentWindow();
    8248    if (window->SkipItems)
    8249       return false;
    8250 
    8251    ImGuiContext& g = *GImGui;
    8252    const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
    8253    return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end);
    8254 }
    8255 
    8256 bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
    8257 {
    8258    ImGuiWindow* window = GetCurrentWindow();
    8259    if (window->SkipItems)
    8260       return false;
    8261 
    8262    ImGuiContext& g = *GImGui;
    8263    const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
    8264    return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end);
    8265 }
    8266 
    8267 bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args)
    8268 {
    8269    return TreeNodeExV(str_id, 0, fmt, args);
    8270 }
    8271 
    8272 bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args)
    8273 {
    8274    return TreeNodeExV(ptr_id, 0, fmt, args);
    8275 }
    8276 
    8277 bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
    8278 {
    8279    va_list args;
    8280    va_start(args, fmt);
    8281    bool is_open = TreeNodeExV(str_id, flags, fmt, args);
    8282    va_end(args);
    8283    return is_open;
    8284 }
    8285 
    8286 bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
    8287 {
    8288    va_list args;
    8289    va_start(args, fmt);
    8290    bool is_open = TreeNodeExV(ptr_id, flags, fmt, args);
    8291    va_end(args);
    8292    return is_open;
    8293 }
    8294 
    8295 bool ImGui::TreeNode(const char* str_id, const char* fmt, ...)
    8296 {
    8297    va_list args;
    8298    va_start(args, fmt);
    8299    bool is_open = TreeNodeExV(str_id, 0, fmt, args);
    8300    va_end(args);
    8301    return is_open;
    8302 }
    8303 
    8304 bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...)
    8305 {
    8306    va_list args;
    8307    va_start(args, fmt);
    8308    bool is_open = TreeNodeExV(ptr_id, 0, fmt, args);
    8309    va_end(args);
    8310    return is_open;
    8311 }
    8312 
    8313 bool ImGui::TreeNode(const char* label)
    8314 {
    8315    ImGuiWindow* window = GetCurrentWindow();
    8316    if (window->SkipItems)
    8317       return false;
    8318    return TreeNodeBehavior(window->GetID(label), 0, label, NULL);
    8319 }
    8320 
    8321 void ImGui::TreeAdvanceToLabelPos()
    8322 {
    8323    ImGuiContext& g = *GImGui;
    8324    g.CurrentWindow->DC.CursorPos.x += GetTreeNodeToLabelSpacing();
    8325 }
    8326 
    8327 // Horizontal distance preceding label when using TreeNode() or Bullet()
    8328 float ImGui::GetTreeNodeToLabelSpacing()
    8329 {
    8330    ImGuiContext& g = *GImGui;
    8331    return g.FontSize + (g.Style.FramePadding.x * 2.0f);
    8332 }
    8333 
    8334 void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond)
    8335 {
    8336    ImGuiContext& g = *GImGui;
    8337    if (g.CurrentWindow->SkipItems)
    8338       return;
    8339    g.NextTreeNodeOpenVal = is_open;
    8340    g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always;
    8341 }
    8342 
    8343 void ImGui::PushID(const char* str_id)
    8344 {
    8345    ImGuiWindow* window = GetCurrentWindowRead();
    8346    window->IDStack.push_back(window->GetID(str_id));
    8347 }
    8348 
    8349 void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
    8350 {
    8351    ImGuiWindow* window = GetCurrentWindowRead();
    8352    window->IDStack.push_back(window->GetID(str_id_begin, str_id_end));
    8353 }
    8354 
    8355 void ImGui::PushID(const void* ptr_id)
    8356 {
    8357    ImGuiWindow* window = GetCurrentWindowRead();
    8358    window->IDStack.push_back(window->GetID(ptr_id));
    8359 }
    8360 
    8361 void ImGui::PushID(int int_id)
    8362 {
    8363    const void* ptr_id = (void*)(intptr_t)int_id;
    8364    ImGuiWindow* window = GetCurrentWindowRead();
    8365    window->IDStack.push_back(window->GetID(ptr_id));
    8366 }
    8367 
    8368 void ImGui::PopID()
    8369 {
    8370    ImGuiWindow* window = GetCurrentWindowRead();
    8371    window->IDStack.pop_back();
    8372 }
    8373 
    8374 ImGuiID ImGui::GetID(const char* str_id)
    8375 {
    8376    return GImGui->CurrentWindow->GetID(str_id);
    8377 }
    8378 
    8379 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
    8380 {
    8381    return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end);
    8382 }
    8383 
    8384 ImGuiID ImGui::GetID(const void* ptr_id)
    8385 {
    8386    return GImGui->CurrentWindow->GetID(ptr_id);
    8387 }
    8388 
    8389 void ImGui::Bullet()
    8390 {
    8391    ImGuiWindow* window = GetCurrentWindow();
    8392    if (window->SkipItems)
    8393       return;
    8394 
    8395    ImGuiContext& g = *GImGui;
    8396    const ImGuiStyle& style = g.Style;
    8397    const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y * 2), g.FontSize);
    8398    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height));
    8399    ItemSize(bb);
    8400    if (!ItemAdd(bb, 0))
    8401    {
    8402       SameLine(0, style.FramePadding.x * 2);
    8403       return;
    8404    }
    8405 
    8406    // Render and stay on same line
    8407    RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
    8408    SameLine(0, style.FramePadding.x * 2);
    8409 }
    8410 
    8411 // Text with a little bullet aligned to the typical tree node.
    8412 void ImGui::BulletTextV(const char* fmt, va_list args)
    8413 {
    8414    ImGuiWindow* window = GetCurrentWindow();
    8415    if (window->SkipItems)
    8416       return;
    8417 
    8418    ImGuiContext& g = *GImGui;
    8419    const ImGuiStyle& style = g.Style;
    8420 
    8421    const char* text_begin = g.TempBuffer;
    8422    const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
    8423    const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
    8424    const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
    8425    const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y * 2), g.FontSize);
    8426    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), ImMax(line_height, label_size.y)));  // Empty text doesn't add padding
    8427    ItemSize(bb);
    8428    if (!ItemAdd(bb, 0))
    8429       return;
    8430 
    8431    // Render
    8432    RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
    8433    RenderText(bb.Min + ImVec2(g.FontSize + style.FramePadding.x * 2, text_base_offset_y), text_begin, text_end, false);
    8434 }
    8435 
    8436 void ImGui::BulletText(const char* fmt, ...)
    8437 {
    8438    va_list args;
    8439    va_start(args, fmt);
    8440    BulletTextV(fmt, args);
    8441    va_end(args);
    8442 }
    8443 
    8444 static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format)
    8445 {
    8446    if (data_type == ImGuiDataType_Int32 || data_type == ImGuiDataType_Uint32)
    8447       return ImFormatString(buf, buf_size, format, *(const int*)data_ptr);
    8448    if (data_type == ImGuiDataType_Float)
    8449       return ImFormatString(buf, buf_size, format, *(const float*)data_ptr);
    8450    if (data_type == ImGuiDataType_Double)
    8451       return ImFormatString(buf, buf_size, format, *(const double*)data_ptr);
    8452    IM_ASSERT(0);
    8453    return 0;
    8454 }
    8455 
    8456 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg1, const void* arg2)
    8457 {
    8458    IM_ASSERT(op == '+' || op == '-');
    8459    if (data_type == ImGuiDataType_Int32)
    8460    {
    8461       if (op == '+')      *(int*)output = *(const int*)arg1 + *(const int*)arg2;
    8462       else if (op == '-') *(int*)output = *(const int*)arg1 - *(const int*)arg2;
    8463    }
    8464    else if (data_type == ImGuiDataType_Uint32)
    8465    {
    8466       if (op == '+')      *(unsigned int*)output = *(const unsigned int*)arg1 + *(const unsigned int*)arg2;
    8467       else if (op == '-') *(unsigned int*)output = *(const unsigned int*)arg1 - *(const unsigned int*)arg2;
    8468    }
    8469    else if (data_type == ImGuiDataType_Float)
    8470    {
    8471       if (op == '+')      *(float*)output = *(const float*)arg1 + *(const float*)arg2;
    8472       else if (op == '-') *(float*)output = *(const float*)arg1 - *(const float*)arg2;
    8473    }
    8474    else if (data_type == ImGuiDataType_Double)
    8475    {
    8476       if (op == '+')      *(double*)output = *(const double*)arg1 + *(const double*)arg2;
    8477       else if (op == '-') *(double*)output = *(const double*)arg1 - *(const double*)arg2;
    8478    }
    8479 }
    8480 
    8481 static size_t GDataTypeSize[ImGuiDataType_COUNT] =
    8482 {
    8483    sizeof(int),
    8484    sizeof(unsigned int),
    8485    sizeof(float),
    8486    sizeof(double)
    8487 };
    8488 
    8489 // User can input math operators (e.g. +100) to edit a numerical values.
    8490 // NB: This is _not_ a full expression evaluator. We should probably add one and replace this dumb mess..
    8491 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format)
    8492 {
    8493    while (ImCharIsSpace((unsigned int)*buf))
    8494       buf++;
    8495 
    8496    // We don't support '-' op because it would conflict with inputing negative value.
    8497    // Instead you can use +-100 to subtract from an existing value
    8498    char op = buf[0];
    8499    if (op == '+' || op == '*' || op == '/')
    8500    {
    8501       buf++;
    8502       while (ImCharIsSpace((unsigned int)*buf))
    8503          buf++;
    8504    }
    8505    else
    8506    {
    8507       op = 0;
    8508    }
    8509    if (!buf[0])
    8510       return false;
    8511 
    8512    IM_ASSERT(data_type < ImGuiDataType_COUNT);
    8513    int data_backup[2];
    8514    IM_ASSERT(GDataTypeSize[data_type] <= sizeof(data_backup));
    8515    memcpy(data_backup, data_ptr, GDataTypeSize[data_type]);
    8516 
    8517    int arg1i = 0;
    8518    float arg1f = 0.0f;
    8519    if (data_type == ImGuiDataType_Int32)
    8520    {
    8521       if (!scalar_format)
    8522          scalar_format = "%d";
    8523       int* v = (int*)data_ptr;
    8524       int arg0i = *v;
    8525       if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1)
    8526          return false;
    8527       // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision
    8528       if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (int)(arg0i + arg1i); }                   // Add (use "+-" to subtract)
    8529       else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (int)(arg0i * arg1f); }                   // Multiply
    8530       else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (int)(arg0i / arg1f); }  // Divide
    8531       else { if (sscanf(buf, scalar_format, &arg0i) == 1) *v = arg0i; }                    // Assign integer constant
    8532    }
    8533    else if (data_type == ImGuiDataType_Uint32)
    8534    {
    8535       if (!scalar_format)
    8536          scalar_format = "%u";
    8537       ImU32* v = (unsigned int*)data_ptr;
    8538       ImU32 arg0i = *v;
    8539       if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1)
    8540          return false;
    8541       // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision
    8542       if (op == '+') { if (sscanf(buf, "%d", &arg1i)) *v = (ImU32)(arg0i + arg1f); }                 // Add (use "+-" to subtract)
    8543       else if (op == '*') { if (sscanf(buf, "%f", &arg1f)) *v = (ImU32)(arg0i * arg1f); }                 // Multiply
    8544       else if (op == '/') { if (sscanf(buf, "%f", &arg1f) && arg1f != 0.0f) *v = (ImU32)(arg0i / arg1f); }// Divide
    8545       else { if (sscanf(buf, scalar_format, &arg0i) == 1) *v = arg0i; }                    // Assign integer constant
    8546    }
    8547    else if (data_type == ImGuiDataType_Float)
    8548    {
    8549       // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in
    8550       scalar_format = "%f";
    8551       float* v = (float*)data_ptr;
    8552       float arg0f = *v;
    8553       if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1)
    8554          return false;
    8555       if (sscanf(buf, scalar_format, &arg1f) < 1)
    8556          return false;
    8557       if (op == '+') { *v = arg0f + arg1f; }                    // Add (use "+-" to subtract)
    8558       else if (op == '*') { *v = arg0f * arg1f; }                    // Multiply
    8559       else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
    8560       else { *v = arg1f; }                            // Assign constant
    8561    }
    8562    else if (data_type == ImGuiDataType_Double)
    8563    {
    8564       scalar_format = "%lf"; // scanf differentiate float/double unlike printf which forces everything to double because of ellipsis
    8565       double* v = (double*)data_ptr;
    8566       double arg0f = *v;
    8567       if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1)
    8568          return false;
    8569       if (sscanf(buf, scalar_format, &arg1f) < 1)
    8570          return false;
    8571       if (op == '+') { *v = arg0f + arg1f; }                    // Add (use "+-" to subtract)
    8572       else if (op == '*') { *v = arg0f * arg1f; }                    // Multiply
    8573       else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
    8574       else { *v = arg1f; }                            // Assign constant
    8575    }
    8576    return memcmp(data_backup, data_ptr, GDataTypeSize[data_type]) != 0;
    8577 }
    8578 
    8579 // Create text input in place of a slider (when CTRL+Clicking on slider)
    8580 // FIXME: Logic is messy and confusing.
    8581 bool ImGui::InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format)
    8582 {
    8583    ImGuiContext& g = *GImGui;
    8584    ImGuiWindow* window = GetCurrentWindow();
    8585 
    8586    // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen)
    8587    // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id
    8588    SetActiveID(g.ScalarAsInputTextId, window);
    8589    g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
    8590    SetHoveredID(0);
    8591    FocusableItemUnregister(window);
    8592 
    8593    char fmt_buf[32];
    8594    char data_buf[32];
    8595    format = ParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf));
    8596    DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, data_ptr, format);
    8597    ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal);
    8598    bool value_changed = InputTextEx(label, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags);
    8599    if (g.ScalarAsInputTextId == 0)     // First frame we started displaying the InputText widget
    8600    {
    8601       IM_ASSERT(g.ActiveId == id);    // InputText ID expected to match the Slider ID
    8602       g.ScalarAsInputTextId = g.ActiveId;
    8603       SetHoveredID(id);
    8604    }
    8605    if (value_changed)
    8606       return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialText.begin(), data_type, data_ptr, NULL);
    8607    return false;
    8608 }
    8609 
    8610 const char* ImGui::ParseFormatTrimDecorationsLeading(const char* fmt)
    8611 {
    8612    while (char c = fmt[0])
    8613    {
    8614       if (c == '%' && fmt[1] != '%')
    8615          return fmt;
    8616       else if (c == '%')
    8617          fmt++;
    8618       fmt++;
    8619    }
    8620    return fmt;
    8621 }
    8622 
    8623 // Extract the format out of a format string with leading or trailing decorations
    8624 //  fmt = "blah blah"  -> return fmt
    8625 //  fmt = "%.3f"       -> return fmt
    8626 //  fmt = "hello %.3f" -> return fmt + 6
    8627 //  fmt = "%.3f hello" -> return buf written with "%.3f"
    8628 const char* ImGui::ParseFormatTrimDecorations(const char* fmt, char* buf, int buf_size)
    8629 {
    8630    // We don't use strchr() because our strings are usually very short and often start with '%'
    8631    const char* fmt_start = ParseFormatTrimDecorationsLeading(fmt);
    8632    if (fmt_start[0] != '%')
    8633       return fmt;
    8634    fmt = fmt_start;
    8635    while (char c = *fmt++)
    8636    {
    8637       if (c >= 'A' && c <= 'Z' && (c != 'L'))  // L is a type modifier, other letters qualify as types aka end of the format
    8638          break;
    8639       if (c >= 'a' && c <= 'z' && (c != 'h' && c != 'j' && c != 'l' && c != 't' && c != 'w' && c != 'z'))  // h/j/l/t/w/z are type modifiers, other letters qualify as types aka end of the format
    8640          break;
    8641    }
    8642    if (fmt[0] == 0) // If we only have leading decoration, we don't need to copy the data.
    8643       return fmt_start;
    8644    ImStrncpy(buf, fmt_start, ImMin((int)(fmt + 1 - fmt_start), buf_size));
    8645    return buf;
    8646 }
    8647 
    8648 // Parse display precision back from the display format string
    8649 // FIXME: This is still used by some navigation code path to infer a minimum tweak step, but we should aim to rework widgets so it isn't needed.
    8650 int ImGui::ParseFormatPrecision(const char* fmt, int default_precision)
    8651 {
    8652    fmt = ParseFormatTrimDecorationsLeading(fmt);
    8653    if (fmt[0] != '%')
    8654       return default_precision;
    8655    fmt++;
    8656    while (*fmt >= '0' && *fmt <= '9')
    8657       fmt++;
    8658    int precision = INT_MAX;
    8659    if (*fmt == '.')
    8660    {
    8661       fmt = ImAtoi(fmt + 1, &precision);
    8662       if (precision < 0 || precision > 99)
    8663          precision = default_precision;
    8664    }
    8665    if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation
    8666       precision = -1;
    8667    if ((*fmt == 'g' || *fmt == 'G') && precision == INT_MAX)
    8668       precision = -1;
    8669    return (precision == INT_MAX) ? default_precision : precision;
    8670 }
    8671 
    8672 static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
    8673 {
    8674    static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f };
    8675    return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : powf(10.0f, (float)-decimal_precision);
    8676 }
    8677 
    8678 float ImGui::RoundScalarWithFormat(const char* format, float value)
    8679 {
    8680    char buf[64];
    8681    ImFormatString(buf, IM_ARRAYSIZE(buf), ParseFormatTrimDecorationsLeading(format), value);
    8682    return (float)atof(buf);
    8683 }
    8684 
    8685 static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos)
    8686 {
    8687    if (v_min == v_max)
    8688       return 0.0f;
    8689 
    8690    const bool is_non_linear = (power < 1.0f - 0.00001f) || (power > 1.0f + 0.00001f);
    8691    const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min);
    8692    if (is_non_linear)
    8693    {
    8694       if (v_clamped < 0.0f)
    8695       {
    8696          const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f, v_max) - v_min);
    8697          return (1.0f - powf(f, 1.0f / power)) * linear_zero_pos;
    8698       }
    8699       else
    8700       {
    8701          const float f = (v_clamped - ImMax(0.0f, v_min)) / (v_max - ImMax(0.0f, v_min));
    8702          return linear_zero_pos + powf(f, 1.0f / power) * (1.0f - linear_zero_pos);
    8703       }
    8704    }
    8705 
    8706    // Linear slider
    8707    return (v_clamped - v_min) / (v_max - v_min);
    8708 }
    8709 
    8710 bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags)
    8711 {
    8712    ImGuiContext& g = *GImGui;
    8713    ImGuiWindow* window = GetCurrentWindow();
    8714    const ImGuiStyle& style = g.Style;
    8715 
    8716    // Draw frame
    8717    const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
    8718    RenderNavHighlight(frame_bb, id);
    8719    RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
    8720 
    8721    const bool is_non_linear = (power < 1.0f - 0.00001f) || (power > 1.0f + 0.00001f);
    8722    const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0;
    8723    const bool is_decimal = ParseFormatPrecision(format, 3) > 0;
    8724 
    8725    const float grab_padding = 2.0f;
    8726    const float slider_sz = is_horizontal ? (frame_bb.GetWidth() - grab_padding * 2.0f) : (frame_bb.GetHeight() - grab_padding * 2.0f);
    8727    float grab_sz;
    8728    if (is_decimal)
    8729       grab_sz = ImMin(style.GrabMinSize, slider_sz);
    8730    else
    8731       grab_sz = ImMin(ImMax(1.0f * (slider_sz / ((v_min < v_max ? v_max - v_min : v_min - v_max) + 1.0f)), style.GrabMinSize), slider_sz);  // Integer sliders, if possible have the grab size represent 1 unit
    8732    const float slider_usable_sz = slider_sz - grab_sz;
    8733    const float slider_usable_pos_min = (is_horizontal ? frame_bb.Min.x : frame_bb.Min.y) + grab_padding + grab_sz * 0.5f;
    8734    const float slider_usable_pos_max = (is_horizontal ? frame_bb.Max.x : frame_bb.Max.y) - grab_padding - grab_sz * 0.5f;
    8735 
    8736    // For logarithmic sliders that cross over sign boundary we want the exponential increase to be symmetric around 0.0f
    8737    float linear_zero_pos = 0.0f;   // 0.0->1.0f
    8738    if (v_min * v_max < 0.0f)
    8739    {
    8740       // Different sign
    8741       const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f / power);
    8742       const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f / power);
    8743       linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0 + linear_dist_max_to_0);
    8744    }
    8745    else
    8746    {
    8747       // Same sign
    8748       linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f;
    8749    }
    8750 
    8751    // Process interacting with the slider
    8752    bool value_changed = false;
    8753    if (g.ActiveId == id)
    8754    {
    8755       bool set_new_value = false;
    8756       float clicked_t = 0.0f;
    8757       if (g.ActiveIdSource == ImGuiInputSource_Mouse)
    8758       {
    8759          if (!g.IO.MouseDown[0])
    8760          {
    8761             ClearActiveID();
    8762          }
    8763          else
    8764          {
    8765             const float mouse_abs_pos = is_horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
    8766             clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f;
    8767             if (!is_horizontal)
    8768                clicked_t = 1.0f - clicked_t;
    8769             set_new_value = true;
    8770          }
    8771       }
    8772       else if (g.ActiveIdSource == ImGuiInputSource_Nav)
    8773       {
    8774          const ImVec2 delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 0.0f, 0.0f);
    8775          float delta = is_horizontal ? delta2.x : -delta2.y;
    8776          if (g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
    8777          {
    8778             ClearActiveID();
    8779          }
    8780          else if (delta != 0.0f)
    8781          {
    8782             clicked_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos);
    8783             if (!is_decimal && !is_non_linear)
     8349        }
     8350    }
     8351
     8352    // 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
     8353    // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
     8354    // 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.
     8355    // 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.
     8356    // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
     8357    if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)  // Check axial match
     8358        if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
     8359            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))
    87848360            {
    8785                if (fabsf(v_max - v_min) <= 100.0f || IsNavInputDown(ImGuiNavInput_TweakSlow))
    8786                   delta = ((delta < 0.0f) ? -1.0f : +1.0f) / (v_max - v_min); // Gamepad/keyboard tweak speeds in integer steps
    8787                else
    8788                   delta /= 100.0f;
     8361                result->DistAxial = dist_axial;
     8362                new_best = true;
    87898363            }
    8790             else
     8364
     8365    return new_best;
     8366}
     8367
     8368// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
     8369static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
     8370{
     8371    ImGuiContext& g = *GImGui;
     8372    //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.
     8373    //    return;
     8374
     8375    const ImGuiItemFlags item_flags = window->DC.ItemFlags;
     8376    const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
     8377
     8378    // Process Init Request
     8379    if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
     8380    {
     8381        // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
     8382        if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
     8383        {
     8384            g.NavInitResultId = id;
     8385            g.NavInitResultRectRel = nav_bb_rel;
     8386        }
     8387        if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
     8388        {
     8389            g.NavInitRequest = false; // Found a match, clear request
     8390            NavUpdateAnyRequestFlag();
     8391        }
     8392    }
     8393
     8394    // Process Move Request (scoring for navigation)
     8395    // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
     8396    if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
     8397    {
     8398        ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
     8399#if IMGUI_DEBUG_NAV_SCORING
     8400        // [DEBUG] Score all items in NavWindow at all times
     8401        if (!g.NavMoveRequest)
     8402            g.NavMoveDir = g.NavMoveDirLast;
     8403        bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
     8404#else
     8405        bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
     8406#endif
     8407        if (new_best)
     8408        {
     8409            result->Window = window;
     8410            result->ID = id;
     8411            result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
     8412            result->RectRel = nav_bb_rel;
     8413        }
     8414
     8415        // Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
     8416        const float VISIBLE_RATIO = 0.70f;
     8417        if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
     8418            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)
     8419                if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb))
     8420                {
     8421                    result = &g.NavMoveResultLocalVisibleSet;
     8422                    result->Window = window;
     8423                    result->ID = id;
     8424                    result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
     8425                    result->RectRel = nav_bb_rel;
     8426                }
     8427    }
     8428
     8429    // Update window-relative bounding box of navigated item
     8430    if (g.NavId == id)
     8431    {
     8432        g.NavWindow = window;                                           // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
     8433        g.NavLayer = window->DC.NavLayerCurrent;
     8434        g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
     8435        g.NavIdIsAlive = true;
     8436        g.NavIdTabCounter = window->DC.FocusCounterTabStop;
     8437        window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel;    // Store item bounding box (relative to window position)
     8438    }
     8439}
     8440
     8441bool ImGui::NavMoveRequestButNoResultYet()
     8442{
     8443    ImGuiContext& g = *GImGui;
     8444    return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
     8445}
     8446
     8447void ImGui::NavMoveRequestCancel()
     8448{
     8449    ImGuiContext& g = *GImGui;
     8450    g.NavMoveRequest = false;
     8451    NavUpdateAnyRequestFlag();
     8452}
     8453
     8454void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags)
     8455{
     8456    ImGuiContext& g = *GImGui;
     8457    IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
     8458    NavMoveRequestCancel();
     8459    g.NavMoveDir = move_dir;
     8460    g.NavMoveClipDir = clip_dir;
     8461    g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
     8462    g.NavMoveRequestFlags = move_flags;
     8463    g.NavWindow->NavRectRel[g.NavLayer] = bb_rel;
     8464}
     8465
     8466void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags)
     8467{
     8468    ImGuiContext& g = *GImGui;
     8469
     8470    // Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
     8471    // popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.
     8472    g.NavWrapRequestWindow = window;
     8473    g.NavWrapRequestFlags = move_flags;
     8474}
     8475
     8476// FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
     8477// This way we could find the last focused window among our children. It would be much less confusing this way?
     8478static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window)
     8479{
     8480    ImGuiWindow* parent = nav_window;
     8481    while (parent && (parent->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
     8482        parent = parent->ParentWindow;
     8483    if (parent && parent != nav_window)
     8484        parent->NavLastChildNavWindow = nav_window;
     8485}
     8486
     8487// Restore the last focused child.
     8488// Call when we are expected to land on the Main Layer (0) after FocusWindow()
     8489static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)
     8490{
     8491    if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive)
     8492        return window->NavLastChildNavWindow;
     8493    return window;
     8494}
     8495
     8496static void NavRestoreLayer(ImGuiNavLayer layer)
     8497{
     8498    ImGuiContext& g = *GImGui;
     8499    g.NavLayer = layer;
     8500    if (layer == 0)
     8501        g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow);
     8502    ImGuiWindow* window = g.NavWindow;
     8503    if (layer == 0 && window->NavLastIds[0] != 0)
     8504        ImGui::SetNavIDWithRectRel(window->NavLastIds[0], layer, 0, window->NavRectRel[0]);
     8505    else
     8506        ImGui::NavInitWindow(window, true);
     8507}
     8508
     8509static inline void ImGui::NavUpdateAnyRequestFlag()
     8510{
     8511    ImGuiContext& g = *GImGui;
     8512    g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
     8513    if (g.NavAnyRequest)
     8514        IM_ASSERT(g.NavWindow != NULL);
     8515}
     8516
     8517// This needs to be called before we submit any widget (aka in or before Begin)
     8518void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
     8519{
     8520    ImGuiContext& g = *GImGui;
     8521    IM_ASSERT(window == g.NavWindow);
     8522    bool init_for_nav = false;
     8523    if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
     8524        if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
     8525            init_for_nav = true;
     8526    IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
     8527    if (init_for_nav)
     8528    {
     8529        SetNavID(0, g.NavLayer, 0);
     8530        g.NavInitRequest = true;
     8531        g.NavInitRequestFromMove = false;
     8532        g.NavInitResultId = 0;
     8533        g.NavInitResultRectRel = ImRect();
     8534        NavUpdateAnyRequestFlag();
     8535    }
     8536    else
     8537    {
     8538        g.NavId = window->NavLastIds[0];
     8539        g.NavFocusScopeId = 0;
     8540    }
     8541}
     8542
     8543static ImVec2 ImGui::NavCalcPreferredRefPos()
     8544{
     8545    ImGuiContext& g = *GImGui;
     8546    if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow)
     8547    {
     8548        // Mouse (we need a fallback in case the mouse becomes invalid after being used)
     8549        if (IsMousePosValid(&g.IO.MousePos))
     8550            return g.IO.MousePos;
     8551        return g.LastValidMousePos;
     8552    }
     8553    else
     8554    {
     8555        // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item.
     8556        const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
     8557        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()));
     8558        ImRect visible_rect = GetViewportRect();
     8559        return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max));   // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta.
     8560    }
     8561}
     8562
     8563float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
     8564{
     8565    ImGuiContext& g = *GImGui;
     8566    if (mode == ImGuiInputReadMode_Down)
     8567        return g.IO.NavInputs[n];                         // Instant, read analog input (0.0f..1.0f, as provided by user)
     8568
     8569    const float t = g.IO.NavInputsDownDuration[n];
     8570    if (t < 0.0f && mode == ImGuiInputReadMode_Released)  // Return 1.0f when just released, no repeat, ignore analog input.
     8571        return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
     8572    if (t < 0.0f)
     8573        return 0.0f;
     8574    if (mode == ImGuiInputReadMode_Pressed)               // Return 1.0f when just pressed, no repeat, ignore analog input.
     8575        return (t == 0.0f) ? 1.0f : 0.0f;
     8576    if (mode == ImGuiInputReadMode_Repeat)
     8577        return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f);
     8578    if (mode == ImGuiInputReadMode_RepeatSlow)
     8579        return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f);
     8580    if (mode == ImGuiInputReadMode_RepeatFast)
     8581        return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f);
     8582    return 0.0f;
     8583}
     8584
     8585ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
     8586{
     8587    ImVec2 delta(0.0f, 0.0f);
     8588    if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
     8589        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode)   - GetNavInputAmount(ImGuiNavInput_KeyLeft_,   mode), GetNavInputAmount(ImGuiNavInput_KeyDown_,   mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_,   mode));
     8590    if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
     8591        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode)   - GetNavInputAmount(ImGuiNavInput_DpadLeft,   mode), GetNavInputAmount(ImGuiNavInput_DpadDown,   mode) - GetNavInputAmount(ImGuiNavInput_DpadUp,   mode));
     8592    if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
     8593        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
     8594    if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
     8595        delta *= slow_factor;
     8596    if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
     8597        delta *= fast_factor;
     8598    return delta;
     8599}
     8600
     8601static void ImGui::NavUpdate()
     8602{
     8603    ImGuiContext& g = *GImGui;
     8604    ImGuiIO& io = g.IO;
     8605
     8606    io.WantSetMousePos = false;
     8607    g.NavWrapRequestWindow = NULL;
     8608    g.NavWrapRequestFlags = ImGuiNavMoveFlags_None;
     8609#if 0
     8610    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);
     8611#endif
     8612
     8613    // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
     8614    // (do it before we map Keyboard input!)
     8615    bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
     8616    bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
     8617    if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_NavGamepad)
     8618    {
     8619        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
     8620            || io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f)
     8621            g.NavInputSource = ImGuiInputSource_NavGamepad;
     8622    }
     8623
     8624    // Update Keyboard->Nav inputs mapping
     8625    if (nav_keyboard_active)
     8626    {
     8627        #define NAV_MAP_KEY(_KEY, _NAV_INPUT)  do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0)
     8628        NAV_MAP_KEY(ImGuiKey_Space,     ImGuiNavInput_Activate );
     8629        NAV_MAP_KEY(ImGuiKey_Enter,     ImGuiNavInput_Input    );
     8630        NAV_MAP_KEY(ImGuiKey_Escape,    ImGuiNavInput_Cancel   );
     8631        NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
     8632        NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
     8633        NAV_MAP_KEY(ImGuiKey_UpArrow,   ImGuiNavInput_KeyUp_   );
     8634        NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
     8635        if (io.KeyCtrl)
     8636            io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
     8637        if (io.KeyShift)
     8638            io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
     8639        if (io.KeyAlt && !io.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu.
     8640            io.NavInputs[ImGuiNavInput_KeyMenu_]  = 1.0f;
     8641        #undef NAV_MAP_KEY
     8642    }
     8643    memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration));
     8644    for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++)
     8645        io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f;
     8646
     8647    // Process navigation init request (select first/default focus)
     8648    if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
     8649        NavUpdateInitResult();
     8650    g.NavInitRequest = false;
     8651    g.NavInitRequestFromMove = false;
     8652    g.NavInitResultId = 0;
     8653    g.NavJustMovedToId = 0;
     8654
     8655    // Process navigation move request
     8656    if (g.NavMoveRequest)
     8657        NavUpdateMoveResult();
     8658
     8659    // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
     8660    if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
     8661    {
     8662        IM_ASSERT(g.NavMoveRequest);
     8663        if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
     8664            g.NavDisableHighlight = false;
     8665        g.NavMoveRequestForward = ImGuiNavForward_None;
     8666    }
     8667
     8668    // Apply application mouse position movement, after we had a chance to process move request result.
     8669    if (g.NavMousePosDirty && g.NavIdIsAlive)
     8670    {
     8671        // Set mouse position given our knowledge of the navigated item position from last frame
     8672        if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
     8673        {
     8674            if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
    87918675            {
    8792                delta /= 100.0f;    // Gamepad/keyboard tweak speeds in % of slider bounds
    8793                if (IsNavInputDown(ImGuiNavInput_TweakSlow))
    8794                   delta /= 10.0f;
     8676                io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos();
     8677                io.WantSetMousePos = true;
    87958678            }
    8796             if (IsNavInputDown(ImGuiNavInput_TweakFast))
    8797                delta *= 10.0f;
    8798             set_new_value = true;
    8799             if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f)) // This is to avoid applying the saturation when already past the limits
    8800                set_new_value = false;
    8801             else
    8802                clicked_t = ImSaturate(clicked_t + delta);
    8803          }
    8804       }
    8805 
    8806       if (set_new_value)
    8807       {
    8808          float new_value;
    8809          if (is_non_linear)
    8810          {
    8811             // Account for logarithmic scale on both sides of the zero
    8812             if (clicked_t < linear_zero_pos)
     8679        }
     8680        g.NavMousePosDirty = false;
     8681    }
     8682    g.NavIdIsAlive = false;
     8683    g.NavJustTabbedId = 0;
     8684    IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
     8685
     8686    // 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
     8687    if (g.NavWindow)
     8688        NavSaveLastChildNavWindowIntoParent(g.NavWindow);
     8689    if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main)
     8690        g.NavWindow->NavLastChildNavWindow = NULL;
     8691
     8692    // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
     8693    NavUpdateWindowing();
     8694
     8695    // Set output flags for user application
     8696    io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
     8697    io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
     8698
     8699    // Process NavCancel input (to close a popup, get back to parent, clear focus)
     8700    if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
     8701    {
     8702        IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
     8703        if (g.ActiveId != 0)
     8704        {
     8705            if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
     8706                ClearActiveID();
     8707        }
     8708        else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
     8709        {
     8710            // Exit child window
     8711            ImGuiWindow* child_window = g.NavWindow;
     8712            ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
     8713            IM_ASSERT(child_window->ChildId != 0);
     8714            FocusWindow(parent_window);
     8715            SetNavID(child_window->ChildId, 0, 0);
     8716            // Reassigning with same value, we're being explicit here.
     8717            g.NavIdIsAlive = false;     // -V1048
     8718            if (g.NavDisableMouseHover)
     8719                g.NavMousePosDirty = true;
     8720        }
     8721        else if (g.OpenPopupStack.Size > 0)
     8722        {
     8723            // Close open popup/menu
     8724            if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
     8725                ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
     8726        }
     8727        else if (g.NavLayer != ImGuiNavLayer_Main)
     8728        {
     8729            // Leave the "menu" layer
     8730            NavRestoreLayer(ImGuiNavLayer_Main);
     8731        }
     8732        else
     8733        {
     8734            // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
     8735            if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
     8736                g.NavWindow->NavLastIds[0] = 0;
     8737            g.NavId = g.NavFocusScopeId = 0;
     8738        }
     8739    }
     8740
     8741    // Process manual activation request
     8742    g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
     8743    if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
     8744    {
     8745        bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
     8746        bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
     8747        if (g.ActiveId == 0 && activate_pressed)
     8748            g.NavActivateId = g.NavId;
     8749        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
     8750            g.NavActivateDownId = g.NavId;
     8751        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
     8752            g.NavActivatePressedId = g.NavId;
     8753        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
     8754            g.NavInputId = g.NavId;
     8755    }
     8756    if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
     8757        g.NavDisableHighlight = true;
     8758    if (g.NavActivateId != 0)
     8759        IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
     8760    g.NavMoveRequest = false;
     8761
     8762    // Process programmatic activation request
     8763    if (g.NavNextActivateId != 0)
     8764        g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
     8765    g.NavNextActivateId = 0;
     8766
     8767    // Initiate directional inputs request
     8768    if (g.NavMoveRequestForward == ImGuiNavForward_None)
     8769    {
     8770        g.NavMoveDir = ImGuiDir_None;
     8771        g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
     8772        if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
     8773        {
     8774            const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
     8775            if (!IsActiveIdUsingNavDir(ImGuiDir_Left)  && (IsNavInputTest(ImGuiNavInput_DpadLeft,  read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_,  read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
     8776            if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
     8777            if (!IsActiveIdUsingNavDir(ImGuiDir_Up)    && (IsNavInputTest(ImGuiNavInput_DpadUp,    read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_,    read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
     8778            if (!IsActiveIdUsingNavDir(ImGuiDir_Down)  && (IsNavInputTest(ImGuiNavInput_DpadDown,  read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_,  read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
     8779        }
     8780        g.NavMoveClipDir = g.NavMoveDir;
     8781    }
     8782    else
     8783    {
     8784        // 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)
     8785        // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
     8786        IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
     8787        IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
     8788        IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
     8789        g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
     8790    }
     8791
     8792    // Update PageUp/PageDown/Home/End scroll
     8793    // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
     8794    float nav_scoring_rect_offset_y = 0.0f;
     8795    if (nav_keyboard_active)
     8796        nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
     8797
     8798    // 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
     8799    if (g.NavMoveDir != ImGuiDir_None)
     8800    {
     8801        g.NavMoveRequest = true;
     8802        g.NavMoveRequestKeyMods = io.KeyMods;
     8803        g.NavMoveDirLast = g.NavMoveDir;
     8804    }
     8805    if (g.NavMoveRequest && g.NavId == 0)
     8806    {
     8807        IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
     8808        g.NavInitRequest = g.NavInitRequestFromMove = true;
     8809        // Reassigning with same value, we're being explicit here.
     8810        g.NavInitResultId = 0;     // -V1048
     8811        g.NavDisableHighlight = false;
     8812    }
     8813    NavUpdateAnyRequestFlag();
     8814
     8815    // Scrolling
     8816    if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
     8817    {
     8818        // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
     8819        ImGuiWindow* window = g.NavWindow;
     8820        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.
     8821        if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
     8822        {
     8823            if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
     8824                SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
     8825            if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
     8826                SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
     8827        }
     8828
     8829        // *Normal* Manual scroll with NavScrollXXX keys
     8830        // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
     8831        ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f);
     8832        if (scroll_dir.x != 0.0f && window->ScrollbarX)
     8833            SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
     8834        if (scroll_dir.y != 0.0f)
     8835            SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
     8836    }
     8837
     8838    // Reset search results
     8839    g.NavMoveResultLocal.Clear();
     8840    g.NavMoveResultLocalVisibleSet.Clear();
     8841    g.NavMoveResultOther.Clear();
     8842
     8843    // When using gamepad, we project the reference nav bounding box into window visible area.
     8844    // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
     8845    // (can't focus a visible object like we can with the mouse).
     8846    if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_NavGamepad && g.NavLayer == ImGuiNavLayer_Main)
     8847    {
     8848        ImGuiWindow* window = g.NavWindow;
     8849        ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
     8850        if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
     8851        {
     8852            IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
     8853            float pad = window->CalcFontSize() * 0.5f;
     8854            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
     8855            window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
     8856            g.NavId = g.NavFocusScopeId = 0;
     8857        }
     8858    }
     8859
     8860    // 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)
     8861    ImRect nav_rect_rel = g.NavWindow ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
     8862    g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect();
     8863    g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
     8864    g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
     8865    g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
     8866    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().
     8867    //GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
     8868    g.NavScoringCount = 0;
     8869#if IMGUI_DEBUG_NAV_RECTS
     8870    if (g.NavWindow)
     8871    {
     8872        ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow);
     8873        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]
     8874        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); }
     8875    }
     8876#endif
     8877}
     8878
     8879static void ImGui::NavUpdateInitResult()
     8880{
     8881    // 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)
     8882    ImGuiContext& g = *GImGui;
     8883    if (!g.NavWindow)
     8884        return;
     8885
     8886    // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
     8887    IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
     8888    if (g.NavInitRequestFromMove)
     8889        SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
     8890    else
     8891        SetNavID(g.NavInitResultId, g.NavLayer, 0);
     8892    g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
     8893}
     8894
     8895// Apply result from previous frame navigation directional move request
     8896static void ImGui::NavUpdateMoveResult()
     8897{
     8898    ImGuiContext& g = *GImGui;
     8899    if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
     8900    {
     8901        // 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)
     8902        if (g.NavId != 0)
     8903        {
     8904            g.NavDisableHighlight = false;
     8905            g.NavDisableMouseHover = true;
     8906        }
     8907        return;
     8908    }
     8909
     8910    // Select which result to use
     8911    ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
     8912
     8913    // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
     8914    if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
     8915        if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId)
     8916            result = &g.NavMoveResultLocalVisibleSet;
     8917
     8918    // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
     8919    if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)
     8920        if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter))
     8921            result = &g.NavMoveResultOther;
     8922    IM_ASSERT(g.NavWindow && result->Window);
     8923
     8924    // Scroll to keep newly navigated item fully into view.
     8925    if (g.NavLayer == ImGuiNavLayer_Main)
     8926    {
     8927        ImVec2 delta_scroll;
     8928        if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge)
     8929        {
     8930            float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
     8931            delta_scroll.y = result->Window->Scroll.y - scroll_target;
     8932            SetScrollY(result->Window, scroll_target);
     8933        }
     8934        else
     8935        {
     8936            ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
     8937            delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
     8938        }
     8939
     8940        // Offset our result position so mouse position can be applied immediately after in NavUpdate()
     8941        result->RectRel.TranslateX(-delta_scroll.x);
     8942        result->RectRel.TranslateY(-delta_scroll.y);
     8943    }
     8944
     8945    ClearActiveID();
     8946    g.NavWindow = result->Window;
     8947    if (g.NavId != result->ID)
     8948    {
     8949        // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
     8950        g.NavJustMovedToId = result->ID;
     8951        g.NavJustMovedToFocusScopeId = result->FocusScopeId;
     8952        g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods;
     8953    }
     8954    IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
     8955    SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
     8956}
     8957
     8958// Handle PageUp/PageDown/Home/End keys
     8959static float ImGui::NavUpdatePageUpPageDown()
     8960{
     8961    ImGuiContext& g = *GImGui;
     8962    ImGuiIO& io = g.IO;
     8963
     8964    if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL)
     8965        return 0.0f;
     8966    if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main)
     8967        return 0.0f;
     8968
     8969    ImGuiWindow* window = g.NavWindow;
     8970    const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
     8971    const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
     8972    const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
     8973    const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
     8974    if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
     8975    {
     8976        if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
     8977        {
     8978            // Fallback manual-scroll when window has no navigable item
     8979            if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
     8980                SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
     8981            else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
     8982                SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
     8983            else if (home_pressed)
     8984                SetScrollY(window, 0.0f);
     8985            else if (end_pressed)
     8986                SetScrollY(window, window->ScrollMax.y);
     8987        }
     8988        else
     8989        {
     8990            ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
     8991            const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
     8992            float nav_scoring_rect_offset_y = 0.0f;
     8993            if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
    88138994            {
    8814                // Negative: rescale to the negative range before powering
    8815                float a = 1.0f - (clicked_t / linear_zero_pos);
    8816                a = powf(a, power);
    8817                new_value = ImLerp(ImMin(v_max, 0.0f), v_min, a);
     8995                nav_scoring_rect_offset_y = -page_offset_y;
     8996                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)
     8997                g.NavMoveClipDir = ImGuiDir_Up;
     8998                g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
    88188999            }
    8819             else
     9000            else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
    88209001            {
    8821                // Positive: rescale to the positive range before powering
    8822                float a;
    8823                if (fabsf(linear_zero_pos - 1.0f) > 1.e-6f)
    8824                   a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos);
    8825                else
    8826                   a = clicked_t;
    8827                a = powf(a, power);
    8828                new_value = ImLerp(ImMax(v_min, 0.0f), v_max, a);
     9002                nav_scoring_rect_offset_y = +page_offset_y;
     9003                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)
     9004                g.NavMoveClipDir = ImGuiDir_Down;
     9005                g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
    88299006            }
    8830          }
    8831          else
    8832          {
    8833             // Linear slider
    8834             new_value = ImLerp(v_min, v_max, clicked_t);
    8835          }
    8836 
    8837          // Round past decimal precision
    8838          new_value = RoundScalarWithFormat(format, new_value);
    8839          if (*v != new_value)
    8840          {
    8841             *v = new_value;
    8842             value_changed = true;
    8843          }
    8844       }
    8845    }
    8846 
    8847    // Draw
    8848    float grab_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos);
    8849    if (!is_horizontal)
    8850       grab_t = 1.0f - grab_t;
    8851    const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
    8852    ImRect grab_bb;
    8853    if (is_horizontal)
    8854       grab_bb = ImRect(ImVec2(grab_pos - grab_sz * 0.5f, frame_bb.Min.y + grab_padding), ImVec2(grab_pos + grab_sz * 0.5f, frame_bb.Max.y - grab_padding));
    8855    else
    8856       grab_bb = ImRect(ImVec2(frame_bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f), ImVec2(frame_bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f));
    8857    window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding);
    8858 
    8859    return value_changed;
    8860 }
    8861 
    8862 // Use power!=1.0 for logarithmic sliders.
    8863 // Adjust format to decorate the value with a prefix or a suffix.
    8864 //   "%.3f"         1.234
    8865 //   "%5.2f secs"   01.23 secs
    8866 //   "Gold: %.0f"   Gold: 1
    8867 bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power)
    8868 {
    8869    ImGuiWindow* window = GetCurrentWindow();
    8870    if (window->SkipItems)
    8871       return false;
    8872 
    8873    ImGuiContext& g = *GImGui;
    8874    const ImGuiStyle& style = g.Style;
    8875    const ImGuiID id = window->GetID(label);
    8876    const float w = CalcItemWidth();
    8877 
    8878    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    8879    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
    8880    const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
    8881 
    8882    // NB- we don't call ItemSize() yet because we may turn into a text edit box below
    8883    if (!ItemAdd(total_bb, id, &frame_bb))
    8884    {
    8885       ItemSize(total_bb, style.FramePadding.y);
    8886       return false;
    8887    }
    8888    const bool hovered = ItemHoverable(frame_bb, id);
    8889 
    8890    if (!format)
    8891       format = "%.3f";
    8892 
    8893    // Tabbing or CTRL-clicking on Slider turns it into an input box
    8894    bool start_text_input = false;
    8895    const bool tab_focus_requested = FocusableItemRegister(window, id);
    8896    if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id))
    8897    {
    8898       SetActiveID(id, window);
    8899       SetFocusID(id, window);
    8900       FocusWindow(window);
    8901       g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
    8902       if (tab_focus_requested || g.IO.KeyCtrl || g.NavInputId == id)
    8903       {
    8904          start_text_input = true;
    8905          g.ScalarAsInputTextId = 0;
    8906       }
    8907    }
    8908    if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
    8909       return InputScalarAsWidgetReplacement(frame_bb, id, label, ImGuiDataType_Float, v, format);
    8910 
    8911    // Actual slider behavior + render grab
    8912    ItemSize(total_bb, style.FramePadding.y);
    8913    const bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, format, power);
    8914 
    8915    // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
    8916    char value_buf[64];
    8917    const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v);
    8918    RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
    8919 
    8920    if (label_size.x > 0.0f)
    8921       RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
    8922 
    8923    return value_changed;
    8924 }
    8925 
    8926 bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format, float power)
    8927 {
    8928    ImGuiWindow* window = GetCurrentWindow();
    8929    if (window->SkipItems)
    8930       return false;
    8931 
    8932    ImGuiContext& g = *GImGui;
    8933    const ImGuiStyle& style = g.Style;
    8934    const ImGuiID id = window->GetID(label);
    8935 
    8936    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    8937    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
    8938    const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
    8939 
    8940    ItemSize(bb, style.FramePadding.y);
    8941    if (!ItemAdd(frame_bb, id))
    8942       return false;
    8943    const bool hovered = ItemHoverable(frame_bb, id);
    8944 
    8945    if (!format)
    8946       format = "%.3f";
    8947 
    8948    if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavInputId == id)
    8949    {
    8950       SetActiveID(id, window);
    8951       SetFocusID(id, window);
    8952       FocusWindow(window);
    8953       g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
    8954    }
    8955 
    8956    // Actual slider behavior + render grab
    8957    bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, format, power, ImGuiSliderFlags_Vertical);
    8958 
    8959    // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
    8960    // For the vertical slider we allow centered text to overlap the frame padding
    8961    char value_buf[64];
    8962    char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v);
    8963    RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f));
    8964    if (label_size.x > 0.0f)
    8965       RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
    8966 
    8967    return value_changed;
    8968 }
    8969 
    8970 bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max)
    8971 {
    8972    float v_deg = (*v_rad) * 360.0f / (2 * IM_PI);
    8973    bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f);
    8974    *v_rad = v_deg * (2 * IM_PI) / 360.0f;
    8975    return value_changed;
    8976 }
    8977 
    8978 bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* format)
    8979 {
    8980    if (!format)
    8981       format = "%.0f";
    8982    float v_f = (float)*v;
    8983    bool value_changed = SliderFloat(label, &v_f, (float)v_min, (float)v_max, format, 1.0f);
    8984    *v = (int)v_f;
    8985    return value_changed;
    8986 }
    8987 
    8988 bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format)
    8989 {
    8990    if (!format)
    8991       format = "%.0f";
    8992    float v_f = (float)*v;
    8993    bool value_changed = VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, format, 1.0f);
    8994    *v = (int)v_f;
    8995    return value_changed;
    8996 }
    8997 
    8998 // Add multiple sliders on 1 line for compact edition of multiple components
    8999 bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* format, float power)
    9000 {
    9001    ImGuiWindow* window = GetCurrentWindow();
    9002    if (window->SkipItems)
    9003       return false;
    9004 
    9005    ImGuiContext& g = *GImGui;
    9006    bool value_changed = false;
    9007    BeginGroup();
    9008    PushID(label);
    9009    PushMultiItemsWidths(components);
    9010    for (int i = 0; i < components; i++)
    9011    {
    9012       PushID(i);
    9013       value_changed |= SliderFloat("##v", &v[i], v_min, v_max, format, power);
    9014       SameLine(0, g.Style.ItemInnerSpacing.x);
    9015       PopID();
    9016       PopItemWidth();
    9017    }
    9018    PopID();
    9019 
    9020    TextUnformatted(label, FindRenderedTextEnd(label));
    9021    EndGroup();
    9022 
    9023    return value_changed;
    9024 }
    9025 
    9026 bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power)
    9027 {
    9028    return SliderFloatN(label, v, 2, v_min, v_max, format, power);
    9029 }
    9030 
    9031 bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power)
    9032 {
    9033    return SliderFloatN(label, v, 3, v_min, v_max, format, power);
    9034 }
    9035 
    9036 bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power)
    9037 {
    9038    return SliderFloatN(label, v, 4, v_min, v_max, format, power);
    9039 }
    9040 
    9041 bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* format)
    9042 {
    9043    ImGuiWindow* window = GetCurrentWindow();
    9044    if (window->SkipItems)
    9045       return false;
    9046 
    9047    ImGuiContext& g = *GImGui;
    9048    bool value_changed = false;
    9049    BeginGroup();
    9050    PushID(label);
    9051    PushMultiItemsWidths(components);
    9052    for (int i = 0; i < components; i++)
    9053    {
    9054       PushID(i);
    9055       value_changed |= SliderInt("##v", &v[i], v_min, v_max, format);
    9056       SameLine(0, g.Style.ItemInnerSpacing.x);
    9057       PopID();
    9058       PopItemWidth();
    9059    }
    9060    PopID();
    9061 
    9062    TextUnformatted(label, FindRenderedTextEnd(label));
    9063    EndGroup();
    9064 
    9065    return value_changed;
    9066 }
    9067 
    9068 bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format)
    9069 {
    9070    return SliderIntN(label, v, 2, v_min, v_max, format);
    9071 }
    9072 
    9073 bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format)
    9074 {
    9075    return SliderIntN(label, v, 3, v_min, v_max, format);
    9076 }
    9077 
    9078 bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format)
    9079 {
    9080    return SliderIntN(label, v, 4, v_min, v_max, format);
    9081 }
    9082 
    9083 bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, const char* format, float power)
    9084 {
    9085    ImGuiContext& g = *GImGui;
    9086    const ImGuiStyle& style = g.Style;
    9087 
    9088    // Draw frame
    9089    const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
    9090    RenderNavHighlight(frame_bb, id);
    9091    RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
    9092 
    9093    // Process interacting with the drag
    9094    if (g.ActiveId == id)
    9095    {
    9096       if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0])
    9097          ClearActiveID();
    9098       else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
    9099          ClearActiveID();
    9100    }
    9101    if (g.ActiveId != id)
    9102       return false;
    9103 
    9104    // Default tweak speed
    9105    if (v_speed == 0.0f && (v_max - v_min) != 0.0f && (v_max - v_min) < FLT_MAX)
    9106       v_speed = (v_max - v_min) * g.DragSpeedDefaultRatio;
    9107 
    9108    if (g.ActiveIdIsJustActivated)
    9109    {
    9110       // Lock current value on click
    9111       g.DragCurrentValue = *v;
    9112       g.DragLastMouseDelta = ImVec2(0.f, 0.f);
    9113    }
    9114 
    9115    const ImVec2 mouse_drag_delta = GetMouseDragDelta(0, 1.0f);
    9116    float adjust_delta = 0.0f;
    9117    if (g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid())
    9118    {
    9119       adjust_delta = mouse_drag_delta.x - g.DragLastMouseDelta.x;
    9120       if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
    9121          adjust_delta *= g.DragSpeedScaleFast;
    9122       if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
    9123          adjust_delta *= g.DragSpeedScaleSlow;
    9124       g.DragLastMouseDelta.x = mouse_drag_delta.x;
    9125    }
    9126    if (g.ActiveIdSource == ImGuiInputSource_Nav)
    9127    {
    9128       int decimal_precision = ParseFormatPrecision(format, 3);
    9129       adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_RepeatFast, 1.0f / 10.0f, 10.0f).x;
    9130       v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision));
    9131    }
    9132    adjust_delta *= v_speed;
    9133 
    9134    // Avoid applying the saturation when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300
    9135    float v_cur = g.DragCurrentValue;
    9136    if (v_min < v_max && ((v_cur >= v_max && adjust_delta > 0.0f) || (v_cur <= v_min && adjust_delta < 0.0f)))
    9137       adjust_delta = 0.0f;
    9138 
    9139    if (fabsf(adjust_delta) > 0.0f)
    9140    {
    9141       if (fabsf(power - 1.0f) > 0.001f)
    9142       {
    9143          // Logarithmic curve on both side of 0.0
    9144          float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur;
    9145          float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f;
    9146          float v1 = powf(v0_abs, 1.0f / power) + (adjust_delta * v0_sign);
    9147          float v1_abs = v1 >= 0.0f ? v1 : -v1;
    9148          float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f;          // Crossed sign line
    9149          v_cur = powf(v1_abs, power) * v0_sign * v1_sign;    // Reapply sign
    9150       }
    9151       else
    9152       {
    9153          v_cur += adjust_delta;
    9154       }
    9155 
    9156       // Clamp
    9157       if (v_min < v_max)
    9158          v_cur = ImClamp(v_cur, v_min, v_max);
    9159       g.DragCurrentValue = v_cur;
    9160    }
    9161 
    9162    // Round to user desired precision, then apply
    9163    bool value_changed = false;
    9164    v_cur = RoundScalarWithFormat(format, v_cur);
    9165    if (*v != v_cur)
    9166    {
    9167       *v = v_cur;
    9168       value_changed = true;
    9169    }
    9170 
    9171    return value_changed;
    9172 }
    9173 
    9174 bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power)
    9175 {
    9176    ImGuiWindow* window = GetCurrentWindow();
    9177    if (window->SkipItems)
    9178       return false;
    9179 
    9180    ImGuiContext& g = *GImGui;
    9181    const ImGuiStyle& style = g.Style;
    9182    const ImGuiID id = window->GetID(label);
    9183    const float w = CalcItemWidth();
    9184 
    9185    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    9186    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
    9187    const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
    9188    const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
    9189 
    9190    // NB- we don't call ItemSize() yet because we may turn into a text edit box below
    9191    if (!ItemAdd(total_bb, id, &frame_bb))
    9192    {
    9193       ItemSize(total_bb, style.FramePadding.y);
    9194       return false;
    9195    }
    9196    const bool hovered = ItemHoverable(frame_bb, id);
    9197 
    9198    if (!format)
    9199       format = "%.3f";
    9200 
    9201    // Tabbing or CTRL-clicking on Drag turns it into an input box
    9202    bool start_text_input = false;
    9203    const bool tab_focus_requested = FocusableItemRegister(window, id);
    9204    if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])) || g.NavActivateId == id || (g.NavInputId == id && g.ScalarAsInputTextId != id))
    9205    {
    9206       SetActiveID(id, window);
    9207       SetFocusID(id, window);
    9208       FocusWindow(window);
    9209       g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
    9210       if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0] || g.NavInputId == id)
    9211       {
    9212          start_text_input = true;
    9213          g.ScalarAsInputTextId = 0;
    9214       }
    9215    }
    9216    if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
    9217       return InputScalarAsWidgetReplacement(frame_bb, id, label, ImGuiDataType_Float, v, format);
    9218 
    9219    // Actual drag behavior
    9220    ItemSize(total_bb, style.FramePadding.y);
    9221    const bool value_changed = DragBehavior(frame_bb, id, v, v_speed, v_min, v_max, format, power);
    9222 
    9223    // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
    9224    char value_buf[64];
    9225    const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), format, *v);
    9226    RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
    9227 
    9228    if (label_size.x > 0.0f)
    9229       RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
    9230 
    9231    return value_changed;
    9232 }
    9233 
    9234 bool ImGui::DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* format, float power)
    9235 {
    9236    ImGuiWindow* window = GetCurrentWindow();
    9237    if (window->SkipItems)
    9238       return false;
    9239 
    9240    ImGuiContext& g = *GImGui;
    9241    bool value_changed = false;
    9242    BeginGroup();
    9243    PushID(label);
    9244    PushMultiItemsWidths(components);
    9245    for (int i = 0; i < components; i++)
    9246    {
    9247       PushID(i);
    9248       value_changed |= DragFloat("##v", &v[i], v_speed, v_min, v_max, format, power);
    9249       SameLine(0, g.Style.ItemInnerSpacing.x);
    9250       PopID();
    9251       PopItemWidth();
    9252    }
    9253    PopID();
    9254 
    9255    TextUnformatted(label, FindRenderedTextEnd(label));
    9256    EndGroup();
    9257 
    9258    return value_changed;
    9259 }
    9260 
    9261 bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power)
    9262 {
    9263    return DragFloatN(label, v, 2, v_speed, v_min, v_max, format, power);
    9264 }
    9265 
    9266 bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power)
    9267 {
    9268    return DragFloatN(label, v, 3, v_speed, v_min, v_max, format, power);
    9269 }
    9270 
    9271 bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power)
    9272 {
    9273    return DragFloatN(label, v, 4, v_speed, v_min, v_max, format, power);
    9274 }
    9275 
    9276 bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* format, const char* format_max, float power)
    9277 {
    9278    ImGuiWindow* window = GetCurrentWindow();
    9279    if (window->SkipItems)
    9280       return false;
    9281 
    9282    ImGuiContext& g = *GImGui;
    9283    PushID(label);
    9284    BeginGroup();
    9285    PushMultiItemsWidths(2);
    9286 
    9287    bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power);
    9288    PopItemWidth();
    9289    SameLine(0, g.Style.ItemInnerSpacing.x);
    9290    value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, format_max ? format_max : format, power);
    9291    PopItemWidth();
    9292    SameLine(0, g.Style.ItemInnerSpacing.x);
    9293 
    9294    TextUnformatted(label, FindRenderedTextEnd(label));
    9295    EndGroup();
    9296    PopID();
    9297 
    9298    return value_changed;
    9299 }
    9300 
    9301 // NB: v_speed is float to allow adjusting the drag speed with more precision
    9302 bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* format)
    9303 {
    9304    if (!format)
    9305       format = "%.0f";
    9306    float v_f = (float)*v;
    9307    bool value_changed = DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, format);
    9308    *v = (int)v_f;
    9309    return value_changed;
    9310 }
    9311 
    9312 bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* format)
    9313 {
    9314    ImGuiWindow* window = GetCurrentWindow();
    9315    if (window->SkipItems)
    9316       return false;
    9317 
    9318    ImGuiContext& g = *GImGui;
    9319    bool value_changed = false;
    9320    BeginGroup();
    9321    PushID(label);
    9322    PushMultiItemsWidths(components);
    9323    for (int i = 0; i < components; i++)
    9324    {
    9325       PushID(i);
    9326       value_changed |= DragInt("##v", &v[i], v_speed, v_min, v_max, format);
    9327       SameLine(0, g.Style.ItemInnerSpacing.x);
    9328       PopID();
    9329       PopItemWidth();
    9330    }
    9331    PopID();
    9332 
    9333    TextUnformatted(label, FindRenderedTextEnd(label));
    9334    EndGroup();
    9335 
    9336    return value_changed;
    9337 }
    9338 
    9339 bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* format)
    9340 {
    9341    return DragIntN(label, v, 2, v_speed, v_min, v_max, format);
    9342 }
    9343 
    9344 bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* format)
    9345 {
    9346    return DragIntN(label, v, 3, v_speed, v_min, v_max, format);
    9347 }
    9348 
    9349 bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* format)
    9350 {
    9351    return DragIntN(label, v, 4, v_speed, v_min, v_max, format);
    9352 }
    9353 
    9354 bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* format, const char* format_max)
    9355 {
    9356    ImGuiWindow* window = GetCurrentWindow();
    9357    if (window->SkipItems)
    9358       return false;
    9359 
    9360    ImGuiContext& g = *GImGui;
    9361    PushID(label);
    9362    BeginGroup();
    9363    PushMultiItemsWidths(2);
    9364 
    9365    bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format);
    9366    PopItemWidth();
    9367    SameLine(0, g.Style.ItemInnerSpacing.x);
    9368    value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, format_max ? format_max : format);
    9369    PopItemWidth();
    9370    SameLine(0, g.Style.ItemInnerSpacing.x);
    9371 
    9372    TextUnformatted(label, FindRenderedTextEnd(label));
    9373    EndGroup();
    9374    PopID();
    9375 
    9376    return value_changed;
    9377 }
    9378 
    9379 void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
    9380 {
    9381    ImGuiWindow* window = GetCurrentWindow();
    9382    if (window->SkipItems)
    9383       return;
    9384 
    9385    ImGuiContext& g = *GImGui;
    9386    const ImGuiStyle& style = g.Style;
    9387 
    9388    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    9389    if (graph_size.x == 0.0f)
    9390       graph_size.x = CalcItemWidth();
    9391    if (graph_size.y == 0.0f)
    9392       graph_size.y = label_size.y + (style.FramePadding.y * 2);
    9393 
    9394    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y));
    9395    const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
    9396    const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));
    9397    ItemSize(total_bb, style.FramePadding.y);
    9398    if (!ItemAdd(total_bb, 0, &frame_bb))
    9399       return;
    9400    const bool hovered = ItemHoverable(inner_bb, 0);
    9401 
    9402    // Determine scale from values if not specified
    9403    if (scale_min == FLT_MAX || scale_max == FLT_MAX)
    9404    {
    9405       float v_min = FLT_MAX;
    9406       float v_max = -FLT_MAX;
    9407       for (int i = 0; i < values_count; i++)
    9408       {
    9409          const float v = values_getter(data, i);
    9410          v_min = ImMin(v_min, v);
    9411          v_max = ImMax(v_max, v);
    9412       }
    9413       if (scale_min == FLT_MAX)
    9414          scale_min = v_min;
    9415       if (scale_max == FLT_MAX)
    9416          scale_max = v_max;
    9417    }
    9418 
    9419    RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
    9420 
    9421    if (values_count > 0)
    9422    {
    9423       int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
    9424       int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
    9425 
    9426       // Tooltip on hover
    9427       int v_hovered = -1;
    9428       if (hovered)
    9429       {
    9430          const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
    9431          const int v_idx = (int)(t * item_count);
    9432          IM_ASSERT(v_idx >= 0 && v_idx < values_count);
    9433 
    9434          const float v0 = values_getter(data, (v_idx + values_offset) % values_count);
    9435          const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count);
    9436          if (plot_type == ImGuiPlotType_Lines)
    9437             SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx + 1, v1);
    9438          else if (plot_type == ImGuiPlotType_Histogram)
    9439             SetTooltip("%d: %8.4g", v_idx, v0);
    9440          v_hovered = v_idx;
    9441       }
    9442 
    9443       const float t_step = 1.0f / (float)res_w;
    9444       const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min));
    9445 
    9446       float v0 = values_getter(data, (0 + values_offset) % values_count);
    9447       float t0 = 0.0f;
    9448       ImVec2 tp0 = ImVec2(t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale));                       // Point in the normalized space of our target rectangle
    9449       float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f);   // Where does the zero line stands
    9450 
    9451       const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);
    9452       const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered);
    9453 
    9454       for (int n = 0; n < res_w; n++)
    9455       {
    9456          const float t1 = t0 + t_step;
    9457          const int v1_idx = (int)(t0 * item_count + 0.5f);
    9458          IM_ASSERT(v1_idx >= 0 && v1_idx < values_count);
    9459          const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count);
    9460          const ImVec2 tp1 = ImVec2(t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale));
    9461 
    9462          // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU.
    9463          ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0);
    9464          ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t));
    9465          if (plot_type == ImGuiPlotType_Lines)
    9466          {
    9467             window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
    9468          }
    9469          else if (plot_type == ImGuiPlotType_Histogram)
    9470          {
    9471             if (pos1.x >= pos0.x + 2.0f)
    9472                pos1.x -= 1.0f;
    9473             window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
    9474          }
    9475 
    9476          t0 = t1;
    9477          tp0 = tp1;
    9478       }
    9479    }
    9480 
    9481    // Text overlay
    9482    if (overlay_text)
    9483       RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f));
    9484 
    9485    if (label_size.x > 0.0f)
    9486       RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
    9487 }
    9488 
    9489 struct ImGuiPlotArrayGetterData
    9490 {
    9491    const float* Values;
    9492    int Stride;
    9493 
    9494    ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; }
    9495 };
    9496 
    9497 static float Plot_ArrayGetter(void* data, int idx)
    9498 {
    9499    ImGuiPlotArrayGetterData* plot_data = (ImGuiPlotArrayGetterData*)data;
    9500    const float v = *(const float*)(const void*)((const unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride);
    9501    return v;
    9502 }
    9503 
    9504 void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
    9505 {
    9506    ImGuiPlotArrayGetterData data(values, stride);
    9507    PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
    9508 }
    9509 
    9510 void ImGui::PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
    9511 {
    9512    PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
    9513 }
    9514 
    9515 void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
    9516 {
    9517    ImGuiPlotArrayGetterData data(values, stride);
    9518    PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
    9519 }
    9520 
    9521 void ImGui::PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
    9522 {
    9523    PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
    9524 }
    9525 
    9526 // size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size
    9527 void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay)
    9528 {
    9529    ImGuiWindow* window = GetCurrentWindow();
    9530    if (window->SkipItems)
    9531       return;
    9532 
    9533    ImGuiContext& g = *GImGui;
    9534    const ImGuiStyle& style = g.Style;
    9535 
    9536    ImVec2 pos = window->DC.CursorPos;
    9537    ImRect bb(pos, pos + CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f));
    9538    ItemSize(bb, style.FramePadding.y);
    9539    if (!ItemAdd(bb, 0))
    9540       return;
    9541 
    9542    // Render
    9543    fraction = ImSaturate(fraction);
    9544    RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
    9545    bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
    9546    const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);
    9547    RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding);
    9548 
    9549    // Default displaying the fraction as percentage string, but user can override it
    9550    char overlay_buf[32];
    9551    if (!overlay)
    9552    {
    9553       ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction * 100 + 0.01f);
    9554       overlay = overlay_buf;
    9555    }
    9556 
    9557    ImVec2 overlay_size = CalcTextSize(overlay, NULL);
    9558    if (overlay_size.x > 0.0f)
    9559       RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb);
    9560 }
    9561 
    9562 bool ImGui::Checkbox(const char* label, bool* v)
    9563 {
    9564    ImGuiWindow* window = GetCurrentWindow();
    9565    if (window->SkipItems)
    9566       return false;
    9567 
    9568    ImGuiContext& g = *GImGui;
    9569    const ImGuiStyle& style = g.Style;
    9570    const ImGuiID id = window->GetID(label);
    9571    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    9572 
    9573    const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y * 2, label_size.y + style.FramePadding.y * 2)); // We want a square shape to we use Y twice
    9574    ItemSize(check_bb, style.FramePadding.y);
    9575 
    9576    ImRect total_bb = check_bb;
    9577    if (label_size.x > 0)
    9578       SameLine(0, style.ItemInnerSpacing.x);
    9579    const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size);
    9580    if (label_size.x > 0)
    9581    {
    9582       ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
    9583       total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max));
    9584    }
    9585 
    9586    if (!ItemAdd(total_bb, id))
    9587       return false;
    9588 
    9589    bool hovered, held;
    9590    bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
    9591    if (pressed)
    9592       *v = !(*v);
    9593 
    9594    RenderNavHighlight(total_bb, id);
    9595    RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
    9596    if (*v)
    9597    {
    9598       const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
    9599       const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
    9600       RenderCheckMark(check_bb.Min + ImVec2(pad, pad), GetColorU32(ImGuiCol_CheckMark), check_bb.GetWidth() - pad * 2.0f);
    9601    }
    9602 
    9603    if (g.LogEnabled)
    9604       LogRenderedText(&text_bb.Min, *v ? "[x]" : "[ ]");
    9605    if (label_size.x > 0.0f)
    9606       RenderText(text_bb.Min, label);
    9607 
    9608    return pressed;
    9609 }
    9610 
    9611 bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value)
    9612 {
    9613    bool v = ((*flags & flags_value) == flags_value);
    9614    bool pressed = Checkbox(label, &v);
    9615    if (pressed)
    9616    {
    9617       if (v)
    9618          *flags |= flags_value;
    9619       else
    9620          *flags &= ~flags_value;
    9621    }
    9622 
    9623    return pressed;
    9624 }
    9625 
    9626 bool ImGui::RadioButton(const char* label, bool active)
    9627 {
    9628    ImGuiWindow* window = GetCurrentWindow();
    9629    if (window->SkipItems)
    9630       return false;
    9631 
    9632    ImGuiContext& g = *GImGui;
    9633    const ImGuiStyle& style = g.Style;
    9634    const ImGuiID id = window->GetID(label);
    9635    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    9636 
    9637    const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y * 2 - 1, label_size.y + style.FramePadding.y * 2 - 1));
    9638    ItemSize(check_bb, style.FramePadding.y);
    9639 
    9640    ImRect total_bb = check_bb;
    9641    if (label_size.x > 0)
    9642       SameLine(0, style.ItemInnerSpacing.x);
    9643    const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size);
    9644    if (label_size.x > 0)
    9645    {
    9646       ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
    9647       total_bb.Add(text_bb);
    9648    }
    9649 
    9650    if (!ItemAdd(total_bb, id))
    9651       return false;
    9652 
    9653    ImVec2 center = check_bb.GetCenter();
    9654    center.x = (float)(int)center.x + 0.5f;
    9655    center.y = (float)(int)center.y + 0.5f;
    9656    const float radius = check_bb.GetHeight() * 0.5f;
    9657 
    9658    bool hovered, held;
    9659    bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
    9660 
    9661    RenderNavHighlight(total_bb, id);
    9662    window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
    9663    if (active)
    9664    {
    9665       const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
    9666       const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
    9667       window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16);
    9668    }
    9669 
    9670    if (style.FrameBorderSize > 0.0f)
    9671    {
    9672       window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize);
    9673       window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize);
    9674    }
    9675 
    9676    if (g.LogEnabled)
    9677       LogRenderedText(&text_bb.Min, active ? "(x)" : "( )");
    9678    if (label_size.x > 0.0f)
    9679       RenderText(text_bb.Min, label);
    9680 
    9681    return pressed;
    9682 }
    9683 
    9684 bool ImGui::RadioButton(const char* label, int* v, int v_button)
    9685 {
    9686    const bool pressed = RadioButton(label, *v == v_button);
    9687    if (pressed)
    9688    {
    9689       *v = v_button;
    9690    }
    9691    return pressed;
    9692 }
    9693 
    9694 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end)
    9695 {
    9696    int line_count = 0;
    9697    const char* s = text_begin;
    9698    while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding
    9699       if (c == '\n')
    9700          line_count++;
    9701    s--;
    9702    if (s[0] != '\n' && s[0] != '\r')
    9703       line_count++;
    9704    *out_text_end = s;
    9705    return line_count;
    9706 }
    9707 
    9708 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
    9709 {
    9710    ImFont* font = GImGui->Font;
    9711    const float line_height = GImGui->FontSize;
    9712    const float scale = line_height / font->FontSize;
    9713 
    9714    ImVec2 text_size = ImVec2(0, 0);
    9715    float line_width = 0.0f;
    9716 
    9717    const ImWchar* s = text_begin;
    9718    while (s < text_end)
    9719    {
    9720       unsigned int c = (unsigned int)(*s++);
    9721       if (c == '\n')
    9722       {
    9723          text_size.x = ImMax(text_size.x, line_width);
    9724          text_size.y += line_height;
    9725          line_width = 0.0f;
    9726          if (stop_on_new_line)
    9727             break;
    9728          continue;
    9729       }
    9730       if (c == '\r')
    9731          continue;
    9732 
    9733       const float char_width = font->GetCharAdvance((unsigned short)c) * scale;
    9734       line_width += char_width;
    9735    }
    9736 
    9737    if (text_size.x < line_width)
    9738       text_size.x = line_width;
    9739 
    9740    if (out_offset)
    9741       *out_offset = ImVec2(line_width, text_size.y + line_height);  // offset allow for the possibility of sitting after a trailing \n
    9742 
    9743    if (line_width > 0 || text_size.y == 0.0f)                        // whereas size.y will ignore the trailing \n
    9744       text_size.y += line_height;
    9745 
    9746    if (remaining)
    9747       *remaining = s;
    9748 
    9749    return text_size;
    9750 }
    9751 
    9752 // Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar)
    9753 namespace ImGuiStb
    9754 {
    9755 
    9756    static int     STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
    9757    static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->Text[idx]; }
    9758    static float   STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->Text[line_start_idx + char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; return GImGui->Font->GetCharAdvance(c) * (GImGui->FontSize / GImGui->Font->FontSize); }
    9759    static int     STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
    9760    static ImWchar STB_TEXTEDIT_NEWLINE = '\n';
    9761    static void    STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx)
    9762    {
    9763       const ImWchar* text = obj->Text.Data;
    9764       const ImWchar* text_remaining = NULL;
    9765       const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
    9766       r->x0 = 0.0f;
    9767       r->x1 = size.x;
    9768       r->baseline_y_delta = size.y;
    9769       r->ymin = 0.0f;
    9770       r->ymax = size.y;
    9771       r->num_chars = (int)(text_remaining - (text + line_start_idx));
    9772    }
    9773 
    9774    static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c == ',' || c == ';' || c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']' || c == '|'; }
    9775    static int  is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator(obj->Text[idx - 1]) && !is_separator(obj->Text[idx])) : 1; }
    9776    static int  STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
    9777 #ifdef __APPLE__    // FIXME: Move setting to IO structure
    9778    static int  is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator(obj->Text[idx - 1]) && is_separator(obj->Text[idx])) : 1; }
    9779    static int  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
    9780 #else
    9781    static int  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
    9782 #endif
    9783 #define STB_TEXTEDIT_MOVEWORDLEFT   STB_TEXTEDIT_MOVEWORDLEFT_IMPL    // They need to be #define for stb_textedit.h
    9784 #define STB_TEXTEDIT_MOVEWORDRIGHT  STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
    9785 
    9786    static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n)
    9787    {
    9788       ImWchar* dst = obj->Text.Data + pos;
    9789 
    9790       // We maintain our buffer length in both UTF-8 and wchar formats
    9791       obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);
    9792       obj->CurLenW -= n;
    9793 
    9794       // Offset remaining text
    9795       const ImWchar* src = obj->Text.Data + pos + n;
    9796       while (ImWchar c = *src++)
    9797          *dst++ = c;
    9798       *dst = '\0';
    9799    }
    9800 
    9801    static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len)
    9802    {
    9803       const int text_len = obj->CurLenW;
    9804       IM_ASSERT(pos <= text_len);
    9805       if (new_text_len + text_len + 1 > obj->Text.Size)
    9806          return false;
    9807 
    9808       const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len);
    9809       if (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufSizeA)
    9810          return false;
    9811 
    9812       ImWchar* text = obj->Text.Data;
    9813       if (pos != text_len)
    9814          memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar));
    9815       memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar));
    9816 
    9817       obj->CurLenW += new_text_len;
    9818       obj->CurLenA += new_text_len_utf8;
    9819       obj->Text[obj->CurLenW] = '\0';
    9820 
    9821       return true;
    9822    }
    9823 
    9824    // We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols)
    9825 #define STB_TEXTEDIT_K_LEFT         0x10000 // keyboard input to move cursor left
    9826 #define STB_TEXTEDIT_K_RIGHT        0x10001 // keyboard input to move cursor right
    9827 #define STB_TEXTEDIT_K_UP           0x10002 // keyboard input to move cursor up
    9828 #define STB_TEXTEDIT_K_DOWN         0x10003 // keyboard input to move cursor down
    9829 #define STB_TEXTEDIT_K_LINESTART    0x10004 // keyboard input to move cursor to start of line
    9830 #define STB_TEXTEDIT_K_LINEEND      0x10005 // keyboard input to move cursor to end of line
    9831 #define STB_TEXTEDIT_K_TEXTSTART    0x10006 // keyboard input to move cursor to start of text
    9832 #define STB_TEXTEDIT_K_TEXTEND      0x10007 // keyboard input to move cursor to end of text
    9833 #define STB_TEXTEDIT_K_DELETE       0x10008 // keyboard input to delete selection or character under cursor
    9834 #define STB_TEXTEDIT_K_BACKSPACE    0x10009 // keyboard input to delete selection or character left of cursor
    9835 #define STB_TEXTEDIT_K_UNDO         0x1000A // keyboard input to perform undo
    9836 #define STB_TEXTEDIT_K_REDO         0x1000B // keyboard input to perform redo
    9837 #define STB_TEXTEDIT_K_WORDLEFT     0x1000C // keyboard input to move cursor left one word
    9838 #define STB_TEXTEDIT_K_WORDRIGHT    0x1000D // keyboard input to move cursor right one word
    9839 #define STB_TEXTEDIT_K_SHIFT        0x20000
    9840 
    9841 #define STB_TEXTEDIT_IMPLEMENTATION
    9842 #include "stb_textedit.h"
    9843 
    9844 }
    9845 
    9846 void ImGuiTextEditState::OnKeyPressed(int key)
    9847 {
    9848    stb_textedit_key(this, &StbState, key);
    9849    CursorFollow = true;
    9850    CursorAnimReset();
    9851 }
    9852 
    9853 // Public API to manipulate UTF-8 text
    9854 // We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar)
    9855 // FIXME: The existence of this rarely exercised code path is a bit of a nuisance.
    9856 void ImGuiTextEditCallbackData::DeleteChars(int pos, int bytes_count)
    9857 {
    9858    IM_ASSERT(pos + bytes_count <= BufTextLen);
    9859    char* dst = Buf + pos;
    9860    const char* src = Buf + pos + bytes_count;
    9861    while (char c = *src++)
    9862       *dst++ = c;
    9863    *dst = '\0';
    9864 
    9865    if (CursorPos + bytes_count >= pos)
    9866       CursorPos -= bytes_count;
    9867    else if (CursorPos >= pos)
    9868       CursorPos = pos;
    9869    SelectionStart = SelectionEnd = CursorPos;
    9870    BufDirty = true;
    9871    BufTextLen -= bytes_count;
    9872 }
    9873 
    9874 void ImGuiTextEditCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
    9875 {
    9876    const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
    9877    if (new_text_len + BufTextLen + 1 >= BufSize)
    9878       return;
    9879 
    9880    if (BufTextLen != pos)
    9881       memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));
    9882    memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char));
    9883    Buf[BufTextLen + new_text_len] = '\0';
    9884 
    9885    if (CursorPos >= pos)
    9886       CursorPos += new_text_len;
    9887    SelectionStart = SelectionEnd = CursorPos;
    9888    BufDirty = true;
    9889    BufTextLen += new_text_len;
    9890 }
    9891 
    9892 // Return false to discard a character.
    9893 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
    9894 {
    9895    unsigned int c = *p_char;
    9896 
    9897    if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF)))
    9898    {
    9899       bool pass = false;
    9900       pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline));
    9901       pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput));
    9902       if (!pass)
    9903          return false;
    9904    }
    9905 
    9906    if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys.
    9907       return false;
    9908 
    9909    if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific))
    9910    {
    9911       if (flags & ImGuiInputTextFlags_CharsDecimal)
    9912          if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
    9913             return false;
    9914 
    9915       if (flags & ImGuiInputTextFlags_CharsScientific)
    9916          if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/') && (c != 'e') && (c != 'E'))
    9917             return false;
    9918 
    9919       if (flags & ImGuiInputTextFlags_CharsHexadecimal)
    9920          if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))
    9921             return false;
    9922 
    9923       if (flags & ImGuiInputTextFlags_CharsUppercase)
    9924          if (c >= 'a' && c <= 'z')
    9925             *p_char = (c += (unsigned int)('A' - 'a'));
    9926 
    9927       if (flags & ImGuiInputTextFlags_CharsNoBlank)
    9928          if (ImCharIsSpace(c))
    9929             return false;
    9930    }
    9931 
    9932    if (flags & ImGuiInputTextFlags_CallbackCharFilter)
    9933    {
    9934       ImGuiTextEditCallbackData callback_data;
    9935       memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
    9936       callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter;
    9937       callback_data.EventChar = (ImWchar)c;
    9938       callback_data.Flags = flags;
    9939       callback_data.UserData = user_data;
    9940       if (callback(&callback_data) != 0)
    9941          return false;
    9942       *p_char = callback_data.EventChar;
    9943       if (!callback_data.EventChar)
    9944          return false;
    9945    }
    9946 
    9947    return true;
    9948 }
    9949 
    9950 // Edit a string of text
    9951 // NB: when active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while active has no effect.
    9952 // FIXME: Rather messy function partly because we are doing UTF8 > u16 > UTF8 conversions on the go to more easily handle stb_textedit calls. Ideally we should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188
    9953 bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
    9954 {
    9955    ImGuiWindow* window = GetCurrentWindow();
    9956    if (window->SkipItems)
    9957       return false;
    9958 
    9959    IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys)
    9960    IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)
    9961 
    9962    ImGuiContext& g = *GImGui;
    9963    const ImGuiIO& io = g.IO;
    9964    const ImGuiStyle& style = g.Style;
    9965 
    9966    const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
    9967    const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
    9968    const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
    9969    const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
    9970 
    9971    if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn
    9972       BeginGroup();
    9973    const ImGuiID id = window->GetID(label);
    9974    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    9975    ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
    9976    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
    9977    const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f));
    9978 
    9979    ImGuiWindow* draw_window = window;
    9980    if (is_multiline)
    9981    {
    9982       ItemAdd(total_bb, id, &frame_bb);
    9983       if (!BeginChildFrame(id, frame_bb.GetSize()))
    9984       {
    9985          EndChildFrame();
    9986          EndGroup();
    9987          return false;
    9988       }
    9989       draw_window = GetCurrentWindow();
    9990       size.x -= draw_window->ScrollbarSizes.x;
    9991    }
    9992    else
    9993    {
    9994       ItemSize(total_bb, style.FramePadding.y);
    9995       if (!ItemAdd(total_bb, id, &frame_bb))
    9996          return false;
    9997    }
    9998    const bool hovered = ItemHoverable(frame_bb, id);
    9999    if (hovered)
    10000       g.MouseCursor = ImGuiMouseCursor_TextInput;
    10001 
    10002    // Password pushes a temporary font with only a fallback glyph
    10003    if (is_password)
    10004    {
    10005       const ImFontGlyph* glyph = g.Font->FindGlyph('*');
    10006       ImFont* password_font = &g.InputTextPasswordFont;
    10007       password_font->FontSize = g.Font->FontSize;
    10008       password_font->Scale = g.Font->Scale;
    10009       password_font->DisplayOffset = g.Font->DisplayOffset;
    10010       password_font->Ascent = g.Font->Ascent;
    10011       password_font->Descent = g.Font->Descent;
    10012       password_font->ContainerAtlas = g.Font->ContainerAtlas;
    10013       password_font->FallbackGlyph = glyph;
    10014       password_font->FallbackAdvanceX = glyph->AdvanceX;
    10015       IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty());
    10016       PushFont(password_font);
    10017    }
    10018 
    10019    // NB: we are only allowed to access 'edit_state' if we are the active widget.
    10020    ImGuiTextEditState& edit_state = g.InputTextState;
    10021 
    10022    const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) == 0);    // Using completion callback disable keyboard tabbing
    10023    const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
    10024    const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
    10025 
    10026    const bool user_clicked = hovered && io.MouseClicked[0];
    10027    const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetIDNoKeepAlive("#SCROLLY");
    10028    const bool user_nav_input_start = (g.ActiveId != id) && ((g.NavInputId == id) || (g.NavActivateId == id && g.NavInputSource == ImGuiInputSource_NavKeyboard));
    10029 
    10030    bool clear_active_id = false;
    10031 
    10032    bool select_all = (g.ActiveId != id) && ((flags & ImGuiInputTextFlags_AutoSelectAll) != 0 || user_nav_input_start) && (!is_multiline);
    10033    if (focus_requested || user_clicked || user_scrolled || user_nav_input_start)
    10034    {
    10035       if (g.ActiveId != id)
    10036       {
    10037          // Start edition
    10038          // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
    10039          // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
    10040          const int prev_len_w = edit_state.CurLenW;
    10041          edit_state.Text.resize(buf_size + 1);        // wchar count <= UTF-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
    10042          edit_state.InitialText.resize(buf_size + 1); // UTF-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
    10043          ImStrncpy(edit_state.InitialText.Data, buf, edit_state.InitialText.Size);
    10044          const char* buf_end = NULL;
    10045          edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
    10046          edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
    10047          edit_state.CursorAnimReset();
    10048 
    10049          // Preserve cursor position and undo/redo stack if we come back to same widget
    10050          // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
    10051          const bool recycle_state = (edit_state.Id == id) && (prev_len_w == edit_state.CurLenW);
    10052          if (recycle_state)
    10053          {
    10054             // Recycle existing cursor/selection/undo stack but clamp position
    10055             // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
    10056             edit_state.CursorClamp();
    10057          }
    10058          else
    10059          {
    10060             edit_state.Id = id;
    10061             edit_state.ScrollX = 0.0f;
    10062             stb_textedit_initialize_state(&edit_state.StbState, !is_multiline);
    10063             if (!is_multiline && focus_requested_by_code)
    10064                select_all = true;
    10065          }
    10066          if (flags & ImGuiInputTextFlags_AlwaysInsertMode)
    10067             edit_state.StbState.insert_mode = true;
    10068          if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
    10069             select_all = true;
    10070       }
    10071       SetActiveID(id, window);
    10072       SetFocusID(id, window);
    10073       FocusWindow(window);
    10074       if (!is_multiline && !(flags & ImGuiInputTextFlags_CallbackHistory))
    10075          g.ActiveIdAllowNavDirFlags |= ((1 << ImGuiDir_Up) | (1 << ImGuiDir_Down));
    10076    }
    10077    else if (io.MouseClicked[0])
    10078    {
    10079       // Release focus when we click outside
    10080       clear_active_id = true;
    10081    }
    10082 
    10083    bool value_changed = false;
    10084    bool enter_pressed = false;
    10085 
    10086    if (g.ActiveId == id)
    10087    {
    10088       if (!is_editable && !g.ActiveIdIsJustActivated)
    10089       {
    10090          // When read-only we always use the live data passed to the function
    10091          edit_state.Text.resize(buf_size + 1);
    10092          const char* buf_end = NULL;
    10093          edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
    10094          edit_state.CurLenA = (int)(buf_end - buf);
    10095          edit_state.CursorClamp();
    10096       }
    10097 
    10098       edit_state.BufSizeA = buf_size;
    10099 
    10100       // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
    10101       // Down the line we should have a cleaner library-wide concept of Selected vs Active.
    10102       g.ActiveIdAllowOverlap = !io.MouseDown[0];
    10103       g.WantTextInputNextFrame = 1;
    10104 
    10105       // Edit in progress
    10106       const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
    10107       const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
    10108 
    10109       const bool is_osx = io.OptMacOSXBehaviors;
    10110       if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0]))
    10111       {
    10112          edit_state.SelectAll();
    10113          edit_state.SelectedAllMouseLock = true;
    10114       }
    10115       else if (hovered && is_osx && io.MouseDoubleClicked[0])
    10116       {
    10117          // Double-click select a word only, OS X style (by simulating keystrokes)
    10118          edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT);
    10119          edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
    10120       }
    10121       else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock)
    10122       {
    10123          if (hovered)
    10124          {
    10125             stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
    10126             edit_state.CursorAnimReset();
    10127          }
    10128       }
    10129       else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
    10130       {
    10131          stb_textedit_drag(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
    10132          edit_state.CursorAnimReset();
    10133          edit_state.CursorFollow = true;
    10134       }
    10135       if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
    10136          edit_state.SelectedAllMouseLock = false;
    10137 
    10138       if (io.InputCharacters[0])
    10139       {
    10140          // Process text input (before we check for Return because using some IME will effectively send a Return?)
    10141          // We ignore CTRL inputs, but need to allow ALT+CTRL as some keyboards (e.g. German) use AltGR (which _is_ Alt+Ctrl) to input certain characters.
    10142          bool ignore_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper);
    10143          if (!ignore_inputs && is_editable && !user_nav_input_start)
    10144             for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++)
     9007            else if (home_pressed)
    101459008            {
    10146                // Insert character if they pass filtering
    10147                unsigned int c = (unsigned int)io.InputCharacters[n];
    10148                if (InputTextFilterCharacter(&c, flags, callback, user_data))
    10149                   edit_state.OnKeyPressed((int)c);
     9009                // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
     9010                // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
     9011                // Preserve current horizontal position if we have any.
     9012                nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
     9013                if (nav_rect_rel.IsInverted())
     9014                    nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
     9015                g.NavMoveDir = ImGuiDir_Down;
     9016                g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
    101509017            }
    10151 
    10152          // Consume characters
    10153          memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
    10154       }
    10155    }
    10156 
    10157    bool cancel_edit = false;
    10158    if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
    10159    {
    10160       // Handle key-presses
    10161       const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
    10162       const bool is_osx = io.OptMacOSXBehaviors;
    10163       const bool is_shortcut_key = (is_osx ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
    10164       const bool is_osx_shift_shortcut = is_osx && io.KeySuper && io.KeyShift && !io.KeyCtrl && !io.KeyAlt;
    10165       const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl;                     // OS X style: Text editing cursor movement using Alt instead of Ctrl
    10166       const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt;  // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
    10167       const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper;
    10168       const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper;
    10169 
    10170       const bool is_cut = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && is_editable && !is_password && (!is_multiline || edit_state.HasSelection());
    10171       const bool is_copy = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only  && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || edit_state.HasSelection());
    10172       const bool is_paste = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && is_editable;
    10173       const bool is_undo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Z)) && is_editable && is_undoable);
    10174       const bool is_redo = ((is_shortcut_key && IsKeyPressedMap(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressedMap(ImGuiKey_Z))) && is_editable && is_undoable;
    10175 
    10176       if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
    10177       else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
    10178       else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
    10179       else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
    10180       else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
    10181       else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
    10182       else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
    10183       else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable)
    10184       {
    10185          if (!edit_state.HasSelection())
    10186          {
    10187             if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT);
    10188             else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT);
    10189          }
    10190          edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
    10191       }
    10192       else if (IsKeyPressedMap(ImGuiKey_Enter))
    10193       {
    10194          bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
    10195          if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
    10196          {
    10197             enter_pressed = clear_active_id = true;
    10198          }
    10199          else if (is_editable)
    10200          {
    10201             unsigned int c = '\n'; // Insert new line
    10202             if (InputTextFilterCharacter(&c, flags, callback, user_data))
    10203                edit_state.OnKeyPressed((int)c);
    10204          }
    10205       }
    10206       else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable)
    10207       {
    10208          unsigned int c = '\t'; // Insert TAB
    10209          if (InputTextFilterCharacter(&c, flags, callback, user_data))
    10210             edit_state.OnKeyPressed((int)c);
    10211       }
    10212       else if (IsKeyPressedMap(ImGuiKey_Escape))
    10213       {
    10214          clear_active_id = cancel_edit = true;
    10215       }
    10216       else if (is_undo || is_redo)
    10217       {
    10218          edit_state.OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);
    10219          edit_state.ClearSelection();
    10220       }
    10221       else if (is_shortcut_key && IsKeyPressedMap(ImGuiKey_A))
    10222       {
    10223          edit_state.SelectAll();
    10224          edit_state.CursorFollow = true;
    10225       }
    10226       else if (is_cut || is_copy)
    10227       {
    10228          // Cut, Copy
    10229          if (io.SetClipboardTextFn)
    10230          {
    10231             const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0;
    10232             const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW;
    10233             edit_state.TempTextBuffer.resize((ie - ib) * 4 + 1);
    10234             ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data + ib, edit_state.Text.Data + ie);
    10235             SetClipboardText(edit_state.TempTextBuffer.Data);
    10236          }
    10237          if (is_cut)
    10238          {
    10239             if (!edit_state.HasSelection())
    10240                edit_state.SelectAll();
    10241             edit_state.CursorFollow = true;
    10242             stb_textedit_cut(&edit_state, &edit_state.StbState);
    10243          }
    10244       }
    10245       else if (is_paste)
    10246       {
    10247          if (const char* clipboard = GetClipboardText())
    10248          {
    10249             // Filter pasted buffer
    10250             const int clipboard_len = (int)strlen(clipboard);
    10251             ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len + 1) * sizeof(ImWchar));
    10252             int clipboard_filtered_len = 0;
    10253             for (const char* s = clipboard; *s; )
     9018            else if (end_pressed)
    102549019            {
    10255                unsigned int c;
    10256                s += ImTextCharFromUtf8(&c, s, NULL);
    10257                if (c == 0)
    10258                   break;
    10259                if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
    10260                   continue;
    10261                clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
     9020                nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
     9021                if (nav_rect_rel.IsInverted())
     9022                    nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
     9023                g.NavMoveDir = ImGuiDir_Up;
     9024                g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
    102629025            }
    10263             clipboard_filtered[clipboard_filtered_len] = 0;
    10264             if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
     9026            return nav_scoring_rect_offset_y;
     9027        }
     9028    }
     9029    return 0.0f;
     9030}
     9031
     9032static void ImGui::NavEndFrame()
     9033{
     9034    ImGuiContext& g = *GImGui;
     9035
     9036    // Show CTRL+TAB list window
     9037    if (g.NavWindowingTarget != NULL)
     9038        NavUpdateWindowingOverlay();
     9039
     9040    // Perform wrap-around in menus
     9041    ImGuiWindow* window = g.NavWrapRequestWindow;
     9042    ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags;
     9043    if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main)
     9044    {
     9045        IM_ASSERT(move_flags != 0); // No points calling this with no wrapping
     9046        ImRect bb_rel = window->NavRectRel[0];
     9047
     9048        ImGuiDir clip_dir = g.NavMoveDir;
     9049        if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
     9050        {
     9051            bb_rel.Min.x = bb_rel.Max.x =
     9052                ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x;
     9053            if (move_flags & ImGuiNavMoveFlags_WrapX)
    102659054            {
    10266                stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
    10267                edit_state.CursorFollow = true;
     9055                bb_rel.TranslateY(-bb_rel.GetHeight());
     9056                clip_dir = ImGuiDir_Up;
    102689057            }
    10269             ImGui::MemFree(clipboard_filtered);
    10270          }
    10271       }
    10272    }
    10273 
    10274    if (g.ActiveId == id)
    10275    {
    10276       if (cancel_edit)
    10277       {
    10278          // Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
    10279          if (is_editable && strncmp(buf, edit_state.InitialText.Data, buf_size) != 0)
    10280          {
    10281             ImStrncpy(buf, edit_state.InitialText.Data, buf_size);
    10282             value_changed = true;
    10283          }
    10284       }
    10285 
    10286       // When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame.
    10287       // If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail. Also this allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage.
    10288       bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
    10289       if (apply_edit_back_to_user_buffer)
    10290       {
    10291          // Apply new value immediately - copy modified buffer back
    10292          // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer
    10293          // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect.
    10294          // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
    10295          if (is_editable)
    10296          {
    10297             edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4);
    10298             ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data, NULL);
    10299          }
    10300 
    10301          // User callback
    10302          if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0)
    10303          {
    10304             IM_ASSERT(callback != NULL);
    10305 
    10306             // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.
    10307             ImGuiInputTextFlags event_flag = 0;
    10308             ImGuiKey event_key = ImGuiKey_COUNT;
    10309             if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab))
     9058            NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
     9059        }
     9060        if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
     9061        {
     9062            bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x;
     9063            if (move_flags & ImGuiNavMoveFlags_WrapX)
    103109064            {
    10311                event_flag = ImGuiInputTextFlags_CallbackCompletion;
    10312                event_key = ImGuiKey_Tab;
     9065                bb_rel.TranslateY(+bb_rel.GetHeight());
     9066                clip_dir = ImGuiDir_Down;
    103139067            }
    10314             else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow))
     9068            NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
     9069        }
     9070        if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
     9071        {
     9072            bb_rel.Min.y = bb_rel.Max.y =
     9073                ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y;
     9074            if (move_flags & ImGuiNavMoveFlags_WrapY)
    103159075            {
    10316                event_flag = ImGuiInputTextFlags_CallbackHistory;
    10317                event_key = ImGuiKey_UpArrow;
     9076                bb_rel.TranslateX(-bb_rel.GetWidth());
     9077                clip_dir = ImGuiDir_Left;
    103189078            }
    10319             else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow))
     9079            NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
     9080        }
     9081        if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
     9082        {
     9083            bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y;
     9084            if (move_flags & ImGuiNavMoveFlags_WrapY)
    103209085            {
    10321                event_flag = ImGuiInputTextFlags_CallbackHistory;
    10322                event_key = ImGuiKey_DownArrow;
     9086                bb_rel.TranslateX(+bb_rel.GetWidth());
     9087                clip_dir = ImGuiDir_Right;
    103239088            }
    10324             else if (flags & ImGuiInputTextFlags_CallbackAlways)
    10325                event_flag = ImGuiInputTextFlags_CallbackAlways;
    10326 
    10327             if (event_flag)
    10328             {
    10329                ImGuiTextEditCallbackData callback_data;
    10330                memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
    10331                callback_data.EventFlag = event_flag;
    10332                callback_data.Flags = flags;
    10333                callback_data.UserData = user_data;
    10334                callback_data.ReadOnly = !is_editable;
    10335 
    10336                callback_data.EventKey = event_key;
    10337                callback_data.Buf = edit_state.TempTextBuffer.Data;
    10338                callback_data.BufTextLen = edit_state.CurLenA;
    10339                callback_data.BufSize = edit_state.BufSizeA;
    10340                callback_data.BufDirty = false;
    10341 
    10342                // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
    10343                ImWchar* text = edit_state.Text.Data;
    10344                const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.cursor);
    10345                const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_start);
    10346                const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_end);
    10347 
    10348                // Call user code
    10349                callback(&callback_data);
    10350 
    10351                // Read back what user may have modified
    10352                IM_ASSERT(callback_data.Buf == edit_state.TempTextBuffer.Data);  // Invalid to modify those fields
    10353                IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA);
    10354                IM_ASSERT(callback_data.Flags == flags);
    10355                if (callback_data.CursorPos != utf8_cursor_pos)            edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos);
    10356                if (callback_data.SelectionStart != utf8_selection_start)  edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart);
    10357                if (callback_data.SelectionEnd != utf8_selection_end)      edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd);
    10358                if (callback_data.BufDirty)
    10359                {
    10360                   IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
    10361                   edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, callback_data.Buf, NULL);
    10362                   edit_state.CurLenA = callback_data.BufTextLen;  // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
    10363                   edit_state.CursorAnimReset();
    10364                }
    10365             }
    10366          }
    10367 
    10368          // Copy back to user buffer
    10369          if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0)
    10370          {
    10371             ImStrncpy(buf, edit_state.TempTextBuffer.Data, buf_size);
    10372             value_changed = true;
    10373          }
    10374       }
    10375    }
    10376 
    10377    // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
    10378    if (clear_active_id && g.ActiveId == id)
    10379       ClearActiveID();
    10380 
    10381    // Render
    10382    // Select which buffer we are going to display. When ImGuiInputTextFlags_NoLiveEdit is set 'buf' might still be the old value. We set buf to NULL to prevent accidental usage from now on.
    10383    const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempTextBuffer.Data : buf; buf = NULL;
    10384 
    10385    RenderNavHighlight(frame_bb, id);
    10386    if (!is_multiline)
    10387       RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
    10388 
    10389    const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size
    10390    ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
    10391    ImVec2 text_size(0.f, 0.f);
    10392    const bool is_currently_scrolling = (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY"));
    10393    if (g.ActiveId == id || is_currently_scrolling)
    10394    {
    10395       edit_state.CursorAnim += io.DeltaTime;
    10396 
    10397       // This is going to be messy. We need to:
    10398       // - Display the text (this alone can be more easily clipped)
    10399       // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
    10400       // - Measure text height (for scrollbar)
    10401       // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
    10402       // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
    10403       const ImWchar* text_begin = edit_state.Text.Data;
    10404       ImVec2 cursor_offset, select_start_offset;
    10405 
    10406       {
    10407          // Count lines + find lines numbers straddling 'cursor' and 'select_start' position.
    10408          const ImWchar* searches_input_ptr[2];
    10409          searches_input_ptr[0] = text_begin + edit_state.StbState.cursor;
    10410          searches_input_ptr[1] = NULL;
    10411          int searches_remaining = 1;
    10412          int searches_result_line_number[2] = { -1, -999 };
    10413          if (edit_state.StbState.select_start != edit_state.StbState.select_end)
    10414          {
    10415             searches_input_ptr[1] = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
    10416             searches_result_line_number[1] = -1;
    10417             searches_remaining++;
    10418          }
    10419 
    10420          // Iterate all lines to find our line numbers
    10421          // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
    10422          searches_remaining += is_multiline ? 1 : 0;
    10423          int line_count = 0;
    10424          for (const ImWchar* s = text_begin; *s != 0; s++)
    10425             if (*s == '\n')
    10426             {
    10427                line_count++;
    10428                if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; }
    10429                if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; }
    10430             }
    10431          line_count++;
    10432          if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count;
    10433          if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count;
    10434 
    10435          // Calculate 2d position by finding the beginning of the line and measuring distance
    10436          cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
    10437          cursor_offset.y = searches_result_line_number[0] * g.FontSize;
    10438          if (searches_result_line_number[1] >= 0)
    10439          {
    10440             select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
    10441             select_start_offset.y = searches_result_line_number[1] * g.FontSize;
    10442          }
    10443 
    10444          // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
    10445          if (is_multiline)
    10446             text_size = ImVec2(size.x, line_count * g.FontSize);
    10447       }
    10448 
    10449       // Scroll
    10450       if (edit_state.CursorFollow)
    10451       {
    10452          // Horizontal scroll in chunks of quarter width
    10453          if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
    10454          {
    10455             const float scroll_increment_x = size.x * 0.25f;
    10456             if (cursor_offset.x < edit_state.ScrollX)
    10457                edit_state.ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
    10458             else if (cursor_offset.x - size.x >= edit_state.ScrollX)
    10459                edit_state.ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
    10460          }
    10461          else
    10462          {
    10463             edit_state.ScrollX = 0.0f;
    10464          }
    10465 
    10466          // Vertical scroll
    10467          if (is_multiline)
    10468          {
    10469             float scroll_y = draw_window->Scroll.y;
    10470             if (cursor_offset.y - g.FontSize < scroll_y)
    10471                scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
    10472             else if (cursor_offset.y - size.y >= scroll_y)
    10473                scroll_y = cursor_offset.y - size.y;
    10474             draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y);   // To avoid a frame of lag
    10475             draw_window->Scroll.y = scroll_y;
    10476             render_pos.y = draw_window->DC.CursorPos.y;
    10477          }
    10478       }
    10479       edit_state.CursorFollow = false;
    10480       const ImVec2 render_scroll = ImVec2(edit_state.ScrollX, 0.0f);
    10481 
    10482       // Draw selection
    10483       if (edit_state.StbState.select_start != edit_state.StbState.select_end)
    10484       {
    10485          const ImWchar* text_selected_begin = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
    10486          const ImWchar* text_selected_end = text_begin + ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end);
    10487 
    10488          float bg_offy_up = is_multiline ? 0.0f : -1.0f;    // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
    10489          float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
    10490          ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg);
    10491          ImVec2 rect_pos = render_pos + select_start_offset - render_scroll;
    10492          for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
    10493          {
    10494             if (rect_pos.y > clip_rect.w + g.FontSize)
    10495                break;
    10496             if (rect_pos.y < clip_rect.y)
    10497             {
    10498                while (p < text_selected_end)
    10499                   if (*p++ == '\n')
    10500                      break;
    10501             }
    10502             else
    10503             {
    10504                ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true);
    10505                if (rect_size.x <= 0.0f) rect_size.x = (float)(int)(g.Font->GetCharAdvance((unsigned short)' ') * 0.50f); // So we can see selected empty lines
    10506                ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn));
    10507                rect.ClipWith(clip_rect);
    10508                if (rect.Overlaps(clip_rect))
    10509                   draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
    10510             }
    10511             rect_pos.x = render_pos.x - render_scroll.x;
    10512             rect_pos.y += g.FontSize;
    10513          }
    10514       }
    10515 
    10516       draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf_display, buf_display + edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect);
    10517 
    10518       // Draw blinking cursor
    10519       bool cursor_is_visible = (!g.IO.OptCursorBlink) || (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f;
    10520       ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll;
    10521       ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y - g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
    10522       if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
    10523          draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
    10524 
    10525       // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
    10526       if (is_editable)
    10527          g.PlatformImePos = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
    10528    }
    10529    else
    10530    {
    10531       // Render text only
    10532       const char* buf_end = NULL;
    10533       if (is_multiline)
    10534          text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width
    10535       draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect);
    10536    }
    10537 
    10538    if (is_multiline)
    10539    {
    10540       Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line
    10541       EndChildFrame();
    10542       EndGroup();
    10543    }
    10544 
    10545    if (is_password)
    10546       PopFont();
    10547 
    10548    // Log as text
    10549    if (g.LogEnabled && !is_password)
    10550       LogRenderedText(&render_pos, buf_display, NULL);
    10551 
    10552    if (label_size.x > 0)
    10553       RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
    10554 
    10555    if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
    10556       return enter_pressed;
    10557    else
    10558       return value_changed;
    10559 }
    10560 
    10561 bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
    10562 {
    10563    IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()
    10564    return InputTextEx(label, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data);
    10565 }
    10566 
    10567 bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
    10568 {
    10569    return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
    10570 }
    10571 
    10572 // NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "format" argument)
    10573 bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags)
    10574 {
    10575    ImGuiWindow* window = GetCurrentWindow();
    10576    if (window->SkipItems)
    10577       return false;
    10578 
    10579    ImGuiContext& g = *GImGui;
    10580    const ImGuiStyle& style = g.Style;
    10581 
    10582    char buf[64];
    10583    DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, data_ptr, scalar_format);
    10584 
    10585    bool value_changed = false;
    10586    if ((extra_flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
    10587       extra_flags |= ImGuiInputTextFlags_CharsDecimal;
    10588    extra_flags |= ImGuiInputTextFlags_AutoSelectAll;
    10589 
    10590    if (step_ptr)
    10591    {
    10592       const float button_size = GetFrameHeight();
    10593 
    10594       BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive()
    10595       PushID(label);
    10596       PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
    10597       if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view
    10598          value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, scalar_format);
    10599       PopItemWidth();
    10600 
    10601       // Step buttons
    10602       SameLine(0, style.ItemInnerSpacing.x);
    10603       if (ButtonEx("-", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups))
    10604       {
    10605          DataTypeApplyOp(data_type, '-', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
    10606          value_changed = true;
    10607       }
    10608       SameLine(0, style.ItemInnerSpacing.x);
    10609       if (ButtonEx("+", ImVec2(button_size, button_size), ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups))
    10610       {
    10611          DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
    10612          value_changed = true;
    10613       }
    10614       SameLine(0, style.ItemInnerSpacing.x);
    10615       TextUnformatted(label, FindRenderedTextEnd(label));
    10616 
    10617       PopID();
    10618       EndGroup();
    10619    }
    10620    else
    10621    {
    10622       if (InputText(label, buf, IM_ARRAYSIZE(buf), extra_flags))
    10623          value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialText.Data, data_type, data_ptr, scalar_format);
    10624    }
    10625 
    10626    return value_changed;
    10627 }
    10628 
    10629 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, const char* format, ImGuiInputTextFlags extra_flags)
    10630 {
    10631    extra_flags |= ImGuiInputTextFlags_CharsScientific;
    10632    return InputScalarEx(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), format, extra_flags);
    10633 }
    10634 
    10635 bool ImGui::InputDouble(const char* label, double* v, double step, double step_fast, const char* format, ImGuiInputTextFlags extra_flags)
    10636 {
    10637    extra_flags |= ImGuiInputTextFlags_CharsScientific;
    10638    return InputScalarEx(label, ImGuiDataType_Double, (void*)v, (void*)(step>0.0 ? &step : NULL), (void*)(step_fast>0.0 ? &step_fast : NULL), format, extra_flags);
    10639 }
    10640 
    10641 bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags)
    10642 {
    10643    // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes.
    10644    const char* format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
    10645    return InputScalarEx(label, ImGuiDataType_Int32, (void*)v, (void*)(step>0 ? &step : NULL), (void*)(step_fast>0 ? &step_fast : NULL), format, extra_flags);
    10646 }
    10647 
    10648 bool ImGui::InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags)
    10649 {
    10650    ImGuiWindow* window = GetCurrentWindow();
    10651    if (window->SkipItems)
    10652       return false;
    10653 
    10654    ImGuiContext& g = *GImGui;
    10655    bool value_changed = false;
    10656    BeginGroup();
    10657    PushID(label);
    10658    PushMultiItemsWidths(components);
    10659    for (int i = 0; i < components; i++)
    10660    {
    10661       PushID(i);
    10662       value_changed |= InputFloat("##v", &v[i], 0, 0, format, extra_flags);
    10663       SameLine(0, g.Style.ItemInnerSpacing.x);
    10664       PopID();
    10665       PopItemWidth();
    10666    }
    10667    PopID();
    10668 
    10669    TextUnformatted(label, FindRenderedTextEnd(label));
    10670    EndGroup();
    10671 
    10672    return value_changed;
    10673 }
    10674 
    10675 bool ImGui::InputFloat2(const char* label, float v[2], const char* format, ImGuiInputTextFlags extra_flags)
    10676 {
    10677    return InputFloatN(label, v, 2, format, extra_flags);
    10678 }
    10679 
    10680 bool ImGui::InputFloat3(const char* label, float v[3], const char* format, ImGuiInputTextFlags extra_flags)
    10681 {
    10682    return InputFloatN(label, v, 3, format, extra_flags);
    10683 }
    10684 
    10685 bool ImGui::InputFloat4(const char* label, float v[4], const char* format, ImGuiInputTextFlags extra_flags)
    10686 {
    10687    return InputFloatN(label, v, 4, format, extra_flags);
    10688 }
    10689 
    10690 // Prefer using "const char* format" directly, which is more flexible and consistent with other API.
    10691 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    10692 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags)
    10693 {
    10694    char format[16] = "%f";
    10695    if (decimal_precision >= 0)
    10696       ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
    10697    return InputFloat(label, v, step, step_fast, format, extra_flags);
    10698 }
    10699 
    10700 bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags)
    10701 {
    10702    char format[16] = "%f";
    10703    if (decimal_precision >= 0)
    10704       ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
    10705    return InputFloatN(label, v, 2, format, extra_flags);
    10706 }
    10707 
    10708 bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags)
    10709 {
    10710    char format[16] = "%f";
    10711    if (decimal_precision >= 0)
    10712       ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
    10713    return InputFloatN(label, v, 3, format, extra_flags);
    10714 }
    10715 
    10716 bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags)
    10717 {
    10718    char format[16] = "%f";
    10719    if (decimal_precision >= 0)
    10720       ImFormatString(format, IM_ARRAYSIZE(format), "%%.%df", decimal_precision);
    10721    return InputFloatN(label, v, 4, format, extra_flags);
    10722 }
    10723 #endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    10724 
    10725 bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags)
    10726 {
    10727    ImGuiWindow* window = GetCurrentWindow();
    10728    if (window->SkipItems)
    10729       return false;
    10730 
    10731    ImGuiContext& g = *GImGui;
    10732    bool value_changed = false;
    10733    BeginGroup();
    10734    PushID(label);
    10735    PushMultiItemsWidths(components);
    10736    for (int i = 0; i < components; i++)
    10737    {
    10738       PushID(i);
    10739       value_changed |= InputInt("##v", &v[i], 0, 0, extra_flags);
    10740       SameLine(0, g.Style.ItemInnerSpacing.x);
    10741       PopID();
    10742       PopItemWidth();
    10743    }
    10744    PopID();
    10745 
    10746    TextUnformatted(label, FindRenderedTextEnd(label));
    10747    EndGroup();
    10748 
    10749    return value_changed;
    10750 }
    10751 
    10752 bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags)
    10753 {
    10754    return InputIntN(label, v, 2, extra_flags);
    10755 }
    10756 
    10757 bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags)
    10758 {
    10759    return InputIntN(label, v, 3, extra_flags);
    10760 }
    10761 
    10762 bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags)
    10763 {
    10764    return InputIntN(label, v, 4, extra_flags);
    10765 }
    10766 
    10767 static float CalcMaxPopupHeightFromItemCount(int items_count)
    10768 {
    10769    ImGuiContext& g = *GImGui;
    10770    if (items_count <= 0)
    10771       return FLT_MAX;
    10772    return (g.FontSize + g.Style.ItemSpacing.y) * items_count - g.Style.ItemSpacing.y + (g.Style.WindowPadding.y * 2);
    10773 }
    10774 
    10775 bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags)
    10776 {
    10777    // Always consume the SetNextWindowSizeConstraint() call in our early return paths
    10778    ImGuiContext& g = *GImGui;
    10779    ImGuiCond backup_next_window_size_constraint = g.NextWindowData.SizeConstraintCond;
    10780    g.NextWindowData.SizeConstraintCond = 0;
    10781 
    10782    ImGuiWindow* window = GetCurrentWindow();
    10783    if (window->SkipItems)
    10784       return false;
    10785 
    10786    IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together
    10787 
    10788    const ImGuiStyle& style = g.Style;
    10789    const ImGuiID id = window->GetID(label);
    10790 
    10791    const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
    10792    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    10793    const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : CalcItemWidth();
    10794    const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
    10795    const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
    10796    ItemSize(total_bb, style.FramePadding.y);
    10797    if (!ItemAdd(total_bb, id, &frame_bb))
    10798       return false;
    10799 
    10800    bool hovered, held;
    10801    bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held);
    10802    bool popup_open = IsPopupOpen(id);
    10803 
    10804    const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f));
    10805    const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
    10806    RenderNavHighlight(frame_bb, id);
    10807    if (!(flags & ImGuiComboFlags_NoPreview))
    10808       window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Max.y), frame_col, style.FrameRounding, ImDrawCornerFlags_Left);
    10809    if (!(flags & ImGuiComboFlags_NoArrowButton))
    10810    {
    10811       window->DrawList->AddRectFilled(ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button), style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right);
    10812       RenderArrow(ImVec2(frame_bb.Max.x - arrow_size + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), ImGuiDir_Down);
    10813    }
    10814    RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding);
    10815    if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))
    10816       RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, preview_value, NULL, NULL, ImVec2(0.0f, 0.0f));
    10817    if (label_size.x > 0)
    10818       RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
    10819 
    10820    if ((pressed || g.NavActivateId == id) && !popup_open)
    10821    {
    10822       if (window->DC.NavLayerCurrent == 0)
    10823          window->NavLastIds[0] = id;
    10824       OpenPopupEx(id);
    10825       popup_open = true;
    10826    }
    10827 
    10828    if (!popup_open)
    10829       return false;
    10830 
    10831    if (backup_next_window_size_constraint)
    10832    {
    10833       g.NextWindowData.SizeConstraintCond = backup_next_window_size_constraint;
    10834       g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w);
    10835    }
    10836    else
    10837    {
    10838       if ((flags & ImGuiComboFlags_HeightMask_) == 0)
    10839          flags |= ImGuiComboFlags_HeightRegular;
    10840       IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_));    // Only one
    10841       int popup_max_height_in_items = -1;
    10842       if (flags & ImGuiComboFlags_HeightRegular)     popup_max_height_in_items = 8;
    10843       else if (flags & ImGuiComboFlags_HeightSmall)  popup_max_height_in_items = 4;
    10844       else if (flags & ImGuiComboFlags_HeightLarge)  popup_max_height_in_items = 20;
    10845       SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
    10846    }
    10847 
    10848    char name[16];
    10849    ImFormatString(name, IM_ARRAYSIZE(name), "##Combo_%02d", g.CurrentPopupStack.Size); // Recycle windows based on depth
    10850 
    10851                                                                                        // Peak into expected window size so we can position it
    10852    if (ImGuiWindow* popup_window = FindWindowByName(name))
    10853       if (popup_window->WasActive)
    10854       {
    10855          ImVec2 size_contents = CalcSizeContents(popup_window);
    10856          ImVec2 size_expected = CalcSizeAfterConstraint(popup_window, CalcSizeAutoFit(popup_window, size_contents));
    10857          if (flags & ImGuiComboFlags_PopupAlignLeft)
    10858             popup_window->AutoPosLastDirection = ImGuiDir_Left;
    10859          ImRect r_outer = FindAllowedExtentRectForWindow(popup_window);
    10860          ImVec2 pos = FindBestWindowPosForPopupEx(frame_bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, frame_bb, ImGuiPopupPositionPolicy_ComboBox);
    10861          SetNextWindowPos(pos);
    10862       }
    10863 
    10864    ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings;
    10865    if (!Begin(name, NULL, window_flags))
    10866    {
    10867       EndPopup();
    10868       IM_ASSERT(0);   // This should never happen as we tested for IsPopupOpen() above
    10869       return false;
    10870    }
    10871 
    10872    // Horizontally align ourselves with the framed text
    10873    if (style.FramePadding.x != style.WindowPadding.x)
    10874       Indent(style.FramePadding.x - style.WindowPadding.x);
    10875 
    10876    return true;
    10877 }
    10878 
    10879 void ImGui::EndCombo()
    10880 {
    10881    const ImGuiStyle& style = GImGui->Style;
    10882    if (style.FramePadding.x != style.WindowPadding.x)
    10883       Unindent(style.FramePadding.x - style.WindowPadding.x);
    10884    EndPopup();
    10885 }
    10886 
    10887 // Old API, prefer using BeginCombo() nowadays if you can.
    10888 bool ImGui::Combo(const char* label, int* current_item, bool(*items_getter)(void*, int, const char**), void* data, int items_count, int popup_max_height_in_items)
    10889 {
    10890    ImGuiContext& g = *GImGui;
    10891 
    10892    const char* preview_text = NULL;
    10893    if (*current_item >= 0 && *current_item < items_count)
    10894       items_getter(data, *current_item, &preview_text);
    10895 
    10896    // The old Combo() API exposed "popup_max_height_in_items", however the new more general BeginCombo() API doesn't, so we emulate it here.
    10897    if (popup_max_height_in_items != -1 && !g.NextWindowData.SizeConstraintCond)
    10898    {
    10899       float popup_max_height = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);
    10900       SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, popup_max_height));
    10901    }
    10902 
    10903    if (!BeginCombo(label, preview_text, 0))
    10904       return false;
    10905 
    10906    // Display items
    10907    // FIXME-OPT: Use clipper (but we need to disable it on the appearing frame to make sure our call to SetItemDefaultFocus() is processed)
    10908    bool value_changed = false;
    10909    for (int i = 0; i < items_count; i++)
    10910    {
    10911       PushID((void*)(intptr_t)i);
    10912       const bool item_selected = (i == *current_item);
    10913       const char* item_text;
    10914       if (!items_getter(data, i, &item_text))
    10915          item_text = "*Unknown item*";
    10916       if (Selectable(item_text, item_selected))
    10917       {
    10918          value_changed = true;
    10919          *current_item = i;
    10920       }
    10921       if (item_selected)
    10922          SetItemDefaultFocus();
    10923       PopID();
    10924    }
    10925 
    10926    EndCombo();
    10927    return value_changed;
    10928 }
    10929 
    10930 static bool Items_ArrayGetter(void* data, int idx, const char** out_text)
    10931 {
    10932    const char* const* items = (const char* const*)data;
    10933    if (out_text)
    10934       *out_text = items[idx];
    10935    return true;
    10936 }
    10937 
    10938 static bool Items_SingleStringGetter(void* data, int idx, const char** out_text)
    10939 {
    10940    // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited.
    10941    const char* items_separated_by_zeros = (const char*)data;
    10942    int items_count = 0;
    10943    const char* p = items_separated_by_zeros;
    10944    while (*p)
    10945    {
    10946       if (idx == items_count)
    10947          break;
    10948       p += strlen(p) + 1;
    10949       items_count++;
    10950    }
    10951    if (!*p)
    10952       return false;
    10953    if (out_text)
    10954       *out_text = p;
    10955    return true;
    10956 }
    10957 
    10958 // Combo box helper allowing to pass an array of strings.
    10959 bool ImGui::Combo(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items)
    10960 {
    10961    const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items);
    10962    return value_changed;
    10963 }
    10964 
    10965 // Combo box helper allowing to pass all items in a single string.
    10966 bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items)
    10967 {
    10968    int items_count = 0;
    10969    const char* p = items_separated_by_zeros;       // FIXME-OPT: Avoid computing this, or at least only when combo is open
    10970    while (*p)
    10971    {
    10972       p += strlen(p) + 1;
    10973       items_count++;
    10974    }
    10975    bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items);
    10976    return value_changed;
    10977 }
    10978 
    10979 // Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image.
    10980 // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID.
    10981 bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
    10982 {
    10983    ImGuiWindow* window = GetCurrentWindow();
    10984    if (window->SkipItems)
    10985       return false;
    10986 
    10987    ImGuiContext& g = *GImGui;
    10988    const ImGuiStyle& style = g.Style;
    10989 
    10990    if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet) // FIXME-OPT: Avoid if vertically clipped.
    10991       PopClipRect();
    10992 
    10993    ImGuiID id = window->GetID(label);
    10994    ImVec2 label_size = CalcTextSize(label, NULL, true);
    10995    ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
    10996    ImVec2 pos = window->DC.CursorPos;
    10997    pos.y += window->DC.CurrentLineTextBaseOffset;
    10998    ImRect bb(pos, pos + size);
    10999    ItemSize(bb);
    11000 
    11001    // Fill horizontal space.
    11002    ImVec2 window_padding = window->WindowPadding;
    11003    float max_x = (flags & ImGuiSelectableFlags_SpanAllColumns) ? GetWindowContentRegionMax().x : GetContentRegionMax().x;
    11004    float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x);
    11005    ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y);
    11006    ImRect bb_with_spacing(pos, pos + size_draw);
    11007    if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth))
    11008       bb_with_spacing.Max.x += window_padding.x;
    11009 
    11010    // Selectables are tightly packed together, we extend the box to cover spacing between selectable.
    11011    float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f);
    11012    float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f);
    11013    float spacing_R = style.ItemSpacing.x - spacing_L;
    11014    float spacing_D = style.ItemSpacing.y - spacing_U;
    11015    bb_with_spacing.Min.x -= spacing_L;
    11016    bb_with_spacing.Min.y -= spacing_U;
    11017    bb_with_spacing.Max.x += spacing_R;
    11018    bb_with_spacing.Max.y += spacing_D;
    11019    if (!ItemAdd(bb_with_spacing, (flags & ImGuiSelectableFlags_Disabled) ? 0 : id))
    11020    {
    11021       if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet)
    11022          PushColumnClipRect();
    11023       return false;
    11024    }
    11025 
    11026    ImGuiButtonFlags button_flags = 0;
    11027    if (flags & ImGuiSelectableFlags_Menu) button_flags |= ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_NoHoldingActiveID;
    11028    if (flags & ImGuiSelectableFlags_MenuItem) button_flags |= ImGuiButtonFlags_PressedOnRelease;
    11029    if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled;
    11030    if (flags & ImGuiSelectableFlags_AllowDoubleClick) button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;
    11031    bool hovered, held;
    11032    bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags);
    11033    if (flags & ImGuiSelectableFlags_Disabled)
    11034       selected = false;
    11035 
    11036    // Hovering selectable with mouse updates NavId accordingly so navigation can be resumed with gamepad/keyboard (this doesn't happen on most widgets)
    11037    if (pressed || hovered)
    11038       if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)
    11039       {
    11040          g.NavDisableHighlight = true;
    11041          SetNavID(id, window->DC.NavLayerCurrent);
    11042       }
    11043 
    11044    // Render
    11045    if (hovered || selected)
    11046    {
    11047       const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
    11048       RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, 0.0f);
    11049       RenderNavHighlight(bb_with_spacing, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
    11050    }
    11051 
    11052    if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsSet)
    11053    {
    11054       PushColumnClipRect();
    11055       bb_with_spacing.Max.x -= (GetContentRegionMax().x - max_x);
    11056    }
    11057 
    11058    if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
    11059    RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size, ImVec2(0.0f, 0.0f));
    11060    if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor();
    11061 
    11062    // Automatically close popups
    11063    if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(window->DC.ItemFlags & ImGuiItemFlags_SelectableDontClosePopup))
    11064       CloseCurrentPopup();
    11065    return pressed;
    11066 }
    11067 
    11068 bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
    11069 {
    11070    if (Selectable(label, *p_selected, flags, size_arg))
    11071    {
    11072       *p_selected = !*p_selected;
    11073       return true;
    11074    }
    11075    return false;
    11076 }
    11077 
    11078 // Helper to calculate the size of a listbox and display a label on the right.
    11079 // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an empty label "##empty"
    11080 bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
    11081 {
    11082    ImGuiWindow* window = GetCurrentWindow();
    11083    if (window->SkipItems)
    11084       return false;
    11085 
    11086    const ImGuiStyle& style = GetStyle();
    11087    const ImGuiID id = GetID(label);
    11088    const ImVec2 label_size = CalcTextSize(label, NULL, true);
    11089 
    11090    // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
    11091    ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y);
    11092    ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));
    11093    ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
    11094    ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
    11095    window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy.
    11096 
    11097    BeginGroup();
    11098    if (label_size.x > 0)
    11099       RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
    11100 
    11101    BeginChildFrame(id, frame_bb.GetSize());
    11102    return true;
    11103 }
    11104 
    11105 bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items)
    11106 {
    11107    // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
    11108    // However we don't add +0.40f if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size.
    11109    // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution.
    11110    if (height_in_items < 0)
    11111       height_in_items = ImMin(items_count, 7);
    11112    float height_in_items_f = height_in_items < items_count ? (height_in_items + 0.40f) : (height_in_items + 0.00f);
    11113 
    11114    // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild().
    11115    ImVec2 size;
    11116    size.x = 0.0f;
    11117    size.y = GetTextLineHeightWithSpacing() * height_in_items_f + GetStyle().ItemSpacing.y;
    11118    return ListBoxHeader(label, size);
    11119 }
    11120 
    11121 void ImGui::ListBoxFooter()
    11122 {
    11123    ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow;
    11124    const ImRect bb = parent_window->DC.LastItemRect;
    11125    const ImGuiStyle& style = GetStyle();
    11126 
    11127    EndChildFrame();
    11128 
    11129    // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect)
    11130    // We call SameLine() to restore DC.CurrentLine* data
    11131    SameLine();
    11132    parent_window->DC.CursorPos = bb.Min;
    11133    ItemSize(bb, style.FramePadding.y);
    11134    EndGroup();
    11135 }
    11136 
    11137 bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items)
    11138 {
    11139    const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items);
    11140    return value_changed;
    11141 }
    11142 
    11143 bool ImGui::ListBox(const char* label, int* current_item, bool(*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items)
    11144 {
    11145    if (!ListBoxHeader(label, items_count, height_in_items))
    11146       return false;
    11147 
    11148    // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper.
    11149    bool value_changed = false;
    11150    ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to.
    11151    while (clipper.Step())
    11152       for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
    11153       {
    11154          const bool item_selected = (i == *current_item);
    11155          const char* item_text;
    11156          if (!items_getter(data, i, &item_text))
    11157             item_text = "*Unknown item*";
    11158 
    11159          PushID(i);
    11160          if (Selectable(item_text, item_selected))
    11161          {
    11162             *current_item = i;
    11163             value_changed = true;
    11164          }
    11165          if (item_selected)
    11166             SetItemDefaultFocus();
    11167          PopID();
    11168       }
    11169    ListBoxFooter();
    11170    return value_changed;
    11171 }
    11172 
    11173 bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled)
    11174 {
    11175    ImGuiWindow* window = GetCurrentWindow();
    11176    if (window->SkipItems)
    11177       return false;
    11178 
    11179    ImGuiContext& g = *GImGui;
    11180    ImGuiStyle& style = g.Style;
    11181    ImVec2 pos = window->DC.CursorPos;
    11182    ImVec2 label_size = CalcTextSize(label, NULL, true);
    11183 
    11184    ImGuiSelectableFlags flags = ImGuiSelectableFlags_MenuItem | (enabled ? 0 : ImGuiSelectableFlags_Disabled);
    11185    bool pressed;
    11186    if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
    11187    {
    11188       // Mimic the exact layout spacing of BeginMenu() to allow MenuItem() inside a menu bar, which is a little misleading but may be useful
    11189       // Note that in this situation we render neither the shortcut neither the selected tick mark
    11190       float w = label_size.x;
    11191       window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
    11192       PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f);
    11193       pressed = Selectable(label, false, flags, ImVec2(w, 0.0f));
    11194       PopStyleVar();
    11195       window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
    11196    }
    11197    else
    11198    {
    11199       ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f);
    11200       float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame
    11201       float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
    11202       pressed = Selectable(label, false, flags | ImGuiSelectableFlags_DrawFillAvailWidth, ImVec2(w, 0.0f));
    11203       if (shortcut_size.x > 0.0f)
    11204       {
    11205          PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
    11206          RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false);
    11207          PopStyleColor();
    11208       }
    11209       if (selected)
    11210          RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled), g.FontSize  * 0.866f);
    11211    }
    11212    return pressed;
    11213 }
    11214 
    11215 bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled)
    11216 {
    11217    if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled))
    11218    {
    11219       if (p_selected)
    11220          *p_selected = !*p_selected;
    11221       return true;
    11222    }
    11223    return false;
    11224 }
    11225 
    11226 // For the main menu bar, which cannot be moved, we honor g.Style.DisplaySafeAreaPadding to ensure text can be visible on a TV set.
    11227 bool ImGui::BeginMainMenuBar()
    11228 {
    11229    ImGuiContext& g = *GImGui;
    11230    g.NextWindowData.MenuBarOffsetMinVal = ImVec2(g.Style.DisplaySafeAreaPadding.x, ImMax(g.Style.DisplaySafeAreaPadding.y - g.Style.FramePadding.y, 0.0f));
    11231    SetNextWindowPos(ImVec2(0.0f, 0.0f));
    11232    SetNextWindowSize(ImVec2(g.IO.DisplaySize.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y));
    11233    PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
    11234    PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0));
    11235    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
    11236    bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
    11237    g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
    11238    if (!is_open)
    11239    {
    11240       End();
    11241       PopStyleVar(2);
    11242       return false;
    11243    }
    11244    return true;
    11245 }
    11246 
    11247 void ImGui::EndMainMenuBar()
    11248 {
    11249    EndMenuBar();
    11250 
    11251    // When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window
    11252    ImGuiContext& g = *GImGui;
    11253    if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0)
    11254       FocusFrontMostActiveWindow(g.NavWindow);
    11255 
    11256    End();
    11257    PopStyleVar(2);
    11258 }
    11259 
    11260 bool ImGui::BeginMenuBar()
    11261 {
    11262    ImGuiWindow* window = GetCurrentWindow();
    11263    if (window->SkipItems)
    11264       return false;
    11265    if (!(window->Flags & ImGuiWindowFlags_MenuBar))
    11266       return false;
    11267 
    11268    IM_ASSERT(!window->DC.MenuBarAppending);
    11269    BeginGroup(); // Save position
    11270    PushID("##menubar");
    11271 
    11272    // We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
    11273    // We remove 1 worth of rounding to Max.x to that text in long menus and small windows don't tend to display over the lower-right rounded area, which looks particularly glitchy.
    11274    ImRect bar_rect = window->MenuBarRect();
    11275    ImRect clip_rect(ImFloor(bar_rect.Min.x + 0.5f), ImFloor(bar_rect.Min.y + window->WindowBorderSize + 0.5f), ImFloor(ImMax(bar_rect.Min.x, bar_rect.Max.x - window->WindowRounding) + 0.5f), ImFloor(bar_rect.Max.y + 0.5f));
    11276    clip_rect.ClipWith(window->WindowRectClipped);
    11277    PushClipRect(clip_rect.Min, clip_rect.Max, false);
    11278 
    11279    window->DC.CursorPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y);
    11280    window->DC.LayoutType = ImGuiLayoutType_Horizontal;
    11281    window->DC.NavLayerCurrent++;
    11282    window->DC.NavLayerCurrentMask <<= 1;
    11283    window->DC.MenuBarAppending = true;
    11284    AlignTextToFramePadding();
    11285    return true;
    11286 }
    11287 
    11288 void ImGui::EndMenuBar()
    11289 {
    11290    ImGuiWindow* window = GetCurrentWindow();
    11291    if (window->SkipItems)
    11292       return;
    11293    ImGuiContext& g = *GImGui;
    11294 
    11295    // Nav: When a move request within one of our child menu failed, capture the request to navigate among our siblings.
    11296    if (NavMoveRequestButNoResultYet() && (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right) && (g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
    11297    {
    11298       ImGuiWindow* nav_earliest_child = g.NavWindow;
    11299       while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
    11300          nav_earliest_child = nav_earliest_child->ParentWindow;
    11301       if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && g.NavMoveRequestForward == ImGuiNavForward_None)
    11302       {
    11303          // To do so we claim focus back, restore NavId and then process the movement request for yet another frame.
    11304          // This involve a one-frame delay which isn't very problematic in this situation. We could remove it by scoring in advance for multiple window (probably not worth the hassle/cost)
    11305          IM_ASSERT(window->DC.NavLayerActiveMaskNext & 0x02); // Sanity check
    11306          FocusWindow(window);
    11307          SetNavIDWithRectRel(window->NavLastIds[1], 1, window->NavRectRel[1]);
    11308          g.NavLayer = 1;
    11309          g.NavDisableHighlight = true; // Hide highlight for the current frame so we don't see the intermediary selection.
    11310          g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
    11311          NavMoveRequestCancel();
    11312       }
    11313    }
    11314 
    11315    IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar);
    11316    IM_ASSERT(window->DC.MenuBarAppending);
    11317    PopClipRect();
    11318    PopID();
    11319    window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos.
    11320    window->DC.GroupStack.back().AdvanceCursor = false;
    11321    EndGroup();
    11322    window->DC.LayoutType = ImGuiLayoutType_Vertical;
    11323    window->DC.NavLayerCurrent--;
    11324    window->DC.NavLayerCurrentMask >>= 1;
    11325    window->DC.MenuBarAppending = false;
    11326 }
    11327 
    11328 bool ImGui::BeginMenu(const char* label, bool enabled)
    11329 {
    11330    ImGuiWindow* window = GetCurrentWindow();
    11331    if (window->SkipItems)
    11332       return false;
    11333 
    11334    ImGuiContext& g = *GImGui;
    11335    const ImGuiStyle& style = g.Style;
    11336    const ImGuiID id = window->GetID(label);
    11337 
    11338    ImVec2 label_size = CalcTextSize(label, NULL, true);
    11339 
    11340    bool pressed;
    11341    bool menu_is_open = IsPopupOpen(id);
    11342    bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].OpenParentId == window->IDStack.back());
    11343    ImGuiWindow* backed_nav_window = g.NavWindow;
    11344    if (menuset_is_open)
    11345       g.NavWindow = window;  // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent)
    11346 
    11347                              // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu (using FindBestWindowPosForPopup).
    11348    ImVec2 popup_pos, pos = window->DC.CursorPos;
    11349    if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
    11350    {
    11351       // Menu inside an horizontal menu bar
    11352       // Selectable extend their highlight by half ItemSpacing in each direction.
    11353       // For ChildMenu, the popup position will be overwritten by the call to FindBestWindowPosForPopup() in Begin()
    11354       popup_pos = ImVec2(pos.x - window->WindowPadding.x, pos.y - style.FramePadding.y + window->MenuBarHeight());
    11355       window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
    11356       PushStyleVar(ImGuiStyleVar_ItemSpacing, style.ItemSpacing * 2.0f);
    11357       float w = label_size.x;
    11358       pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
    11359       PopStyleVar();
    11360       window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
    11361    }
    11362    else
    11363    {
    11364       // Menu inside a menu
    11365       popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
    11366       float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame
    11367       float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
    11368       pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
    11369       if (!enabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
    11370       RenderArrow(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), ImGuiDir_Right);
    11371       if (!enabled) PopStyleColor();
    11372    }
    11373 
    11374    const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id);
    11375    if (menuset_is_open)
    11376       g.NavWindow = backed_nav_window;
    11377 
    11378    bool want_open = false, want_close = false;
    11379    if (window->DC.LayoutType == ImGuiLayoutType_Vertical) // (window->Flags & (ImGuiWindowFlags_Popup|ImGuiWindowFlags_ChildMenu))
    11380    {
    11381       // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
    11382       bool moving_within_opened_triangle = false;
    11383       if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window && !(window->Flags & ImGuiWindowFlags_MenuBar))
    11384       {
    11385          if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window)
    11386          {
    11387             ImRect next_window_rect = next_window->Rect();
    11388             ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
    11389             ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR();
    11390             ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR();
    11391             float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack.
    11392             ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f;   // to avoid numerical issues
    11393             tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f);            // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale?
    11394             tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f);
    11395             moving_within_opened_triangle = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);
    11396             //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); window->DrawList->PopClipRect(); // Debug
    11397          }
    11398       }
    11399 
    11400       want_close = (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle);
    11401       want_open = (!menu_is_open && hovered && !moving_within_opened_triangle) || (!menu_is_open && hovered && pressed);
    11402 
    11403       if (g.NavActivateId == id)
    11404       {
    11405          want_close = menu_is_open;
    11406          want_open = !menu_is_open;
    11407       }
    11408       if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Right) // Nav-Right to open
    11409       {
    11410          want_open = true;
    11411          NavMoveRequestCancel();
    11412       }
    11413    }
    11414    else
    11415    {
    11416       // Menu bar
    11417       if (menu_is_open && pressed && menuset_is_open) // Click an open menu again to close it
    11418       {
    11419          want_close = true;
    11420          want_open = menu_is_open = false;
    11421       }
    11422       else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // First click to open, then hover to open others
    11423       {
    11424          want_open = true;
    11425       }
    11426       else if (g.NavId == id && g.NavMoveRequest && g.NavMoveDir == ImGuiDir_Down) // Nav-Down to open
    11427       {
    11428          want_open = true;
    11429          NavMoveRequestCancel();
    11430       }
    11431    }
    11432 
    11433    if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }'
    11434       want_close = true;
    11435    if (want_close && IsPopupOpen(id))
    11436       ClosePopupToLevel(g.CurrentPopupStack.Size);
    11437 
    11438    if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size)
    11439    {
    11440       // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame.
    11441       OpenPopup(label);
    11442       return false;
    11443    }
    11444 
    11445    menu_is_open |= want_open;
    11446    if (want_open)
    11447       OpenPopup(label);
    11448 
    11449    if (menu_is_open)
    11450    {
    11451       // Sub-menus are ChildWindow so that mouse can be hovering across them (otherwise top-most popup menu would steal focus and not allow hovering on parent menu)
    11452       SetNextWindowPos(popup_pos, ImGuiCond_Always);
    11453       ImGuiWindowFlags flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ((window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) ? ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_ChildWindow : ImGuiWindowFlags_ChildMenu);
    11454       menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
    11455    }
    11456 
    11457    return menu_is_open;
    11458 }
    11459 
    11460 void ImGui::EndMenu()
    11461 {
    11462    // Nav: When a left move request _within our child menu_ failed, close the menu.
    11463    // A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs.
    11464    // However it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction.
    11465    ImGuiContext& g = *GImGui;
    11466    ImGuiWindow* window = g.CurrentWindow;
    11467    if (g.NavWindow && g.NavWindow->ParentWindow == window && g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
    11468    {
    11469       ClosePopupToLevel(g.OpenPopupStack.Size - 1);
    11470       NavMoveRequestCancel();
    11471    }
    11472 
    11473    EndPopup();
    11474 }
    11475 
    11476 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
    11477 void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags)
    11478 {
    11479    ImGuiContext& g = *GImGui;
    11480 
    11481    int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
    11482    BeginTooltipEx(0, true);
    11483 
    11484    const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;
    11485    if (text_end > text)
    11486    {
    11487       TextUnformatted(text, text_end);
    11488       Separator();
    11489    }
    11490 
    11491    ImVec2 sz(g.FontSize * 3 + g.Style.FramePadding.y * 2, g.FontSize * 3 + g.Style.FramePadding.y * 2);
    11492    ColorButton("##preview", ImVec4(col[0], col[1], col[2], col[3]), (flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz);
    11493    SameLine();
    11494    if (flags & ImGuiColorEditFlags_NoAlpha)
    11495       Text("#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]);
    11496    else
    11497       Text("#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]);
    11498    EndTooltip();
    11499 }
    11500 
    11501 static inline ImU32 ImAlphaBlendColor(ImU32 col_a, ImU32 col_b)
    11502 {
    11503    float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
    11504    int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
    11505    int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
    11506    int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
    11507    return IM_COL32(r, g, b, 0xFF);
    11508 }
    11509 
    11510 // NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that.
    11511 // I spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding alltogether.
    11512 void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags)
    11513 {
    11514    ImGuiWindow* window = GetCurrentWindow();
    11515    if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
    11516    {
    11517       ImU32 col_bg1 = GetColorU32(ImAlphaBlendColor(IM_COL32(204, 204, 204, 255), col));
    11518       ImU32 col_bg2 = GetColorU32(ImAlphaBlendColor(IM_COL32(128, 128, 128, 255), col));
    11519       window->DrawList->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags);
    11520 
    11521       int yi = 0;
    11522       for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)
    11523       {
    11524          float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
    11525          if (y2 <= y1)
     9089            NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
     9090        }
     9091    }
     9092}
     9093
     9094static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N)
     9095{
     9096    ImGuiContext& g = *GImGui;
     9097    for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--)
     9098        if (g.WindowsFocusOrder[i] == window)
     9099            return i;
     9100    return -1;
     9101}
     9102
     9103static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
     9104{
     9105    ImGuiContext& g = *GImGui;
     9106    for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)
     9107        if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i]))
     9108            return g.WindowsFocusOrder[i];
     9109    return NULL;
     9110}
     9111
     9112static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
     9113{
     9114    ImGuiContext& g = *GImGui;
     9115    IM_ASSERT(g.NavWindowingTarget);
     9116    if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
     9117        return;
     9118
     9119    const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget);
     9120    ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
     9121    if (!window_target)
     9122        window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);
     9123    if (window_target) // Don't reset windowing target if there's a single window in the list
     9124        g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
     9125    g.NavWindowingToggleLayer = false;
     9126}
     9127
     9128// Windowing management mode
     9129// Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer)
     9130// Gamepad:  Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer)
     9131static void ImGui::NavUpdateWindowing()
     9132{
     9133    ImGuiContext& g = *GImGui;
     9134    ImGuiWindow* apply_focus_window = NULL;
     9135    bool apply_toggle_layer = false;
     9136
     9137    ImGuiWindow* modal_window = GetTopMostPopupModal();
     9138    bool allow_windowing = (modal_window == NULL);
     9139    if (!allow_windowing)
     9140        g.NavWindowingTarget = NULL;
     9141
     9142    // Fade out
     9143    if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
     9144    {
     9145        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f);
     9146        if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
     9147            g.NavWindowingTargetAnim = NULL;
     9148    }
     9149
     9150    // Start CTRL-TAB or Square+L/R window selection
     9151    bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
     9152    bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
     9153    if (start_windowing_with_gamepad || start_windowing_with_keyboard)
     9154        if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
     9155        {
     9156            g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // FIXME-DOCK: Will need to use RootWindowDockStop
     9157            g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
     9158            g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
     9159            g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
     9160        }
     9161
     9162    // Gamepad update
     9163    g.NavWindowingTimer += g.IO.DeltaTime;
     9164    if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad)
     9165    {
     9166        // 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
     9167        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
     9168
     9169        // Select window to focus
     9170        const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
     9171        if (focus_change_dir != 0)
     9172        {
     9173            NavUpdateWindowingHighlightWindow(focus_change_dir);
     9174            g.NavWindowingHighlightAlpha = 1.0f;
     9175        }
     9176
     9177        // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)
     9178        if (!IsNavInputDown(ImGuiNavInput_Menu))
     9179        {
     9180            g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
     9181            if (g.NavWindowingToggleLayer && g.NavWindow)
     9182                apply_toggle_layer = true;
     9183            else if (!g.NavWindowingToggleLayer)
     9184                apply_focus_window = g.NavWindowingTarget;
     9185            g.NavWindowingTarget = NULL;
     9186        }
     9187    }
     9188
     9189    // Keyboard: Focus
     9190    if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard)
     9191    {
     9192        // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
     9193        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
     9194        if (IsKeyPressedMap(ImGuiKey_Tab, true))
     9195            NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
     9196        if (!g.IO.KeyCtrl)
     9197            apply_focus_window = g.NavWindowingTarget;
     9198    }
     9199
     9200    // Keyboard: Press and Release ALT to toggle menu layer
     9201    // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB
     9202    if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed))
     9203        g.NavWindowingToggleLayer = true;
     9204    if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
     9205        if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
     9206            apply_toggle_layer = true;
     9207
     9208    // Move window
     9209    if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
     9210    {
     9211        ImVec2 move_delta;
     9212        if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift)
     9213            move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
     9214        if (g.NavInputSource == ImGuiInputSource_NavGamepad)
     9215            move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
     9216        if (move_delta.x != 0.0f || move_delta.y != 0.0f)
     9217        {
     9218            const float NAV_MOVE_SPEED = 800.0f;
     9219            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
     9220            ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow;
     9221            SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always);
     9222            MarkIniSettingsDirty(moving_window);
     9223            g.NavDisableMouseHover = true;
     9224        }
     9225    }
     9226
     9227    // Apply final focus
     9228    if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
     9229    {
     9230        ClearActiveID();
     9231        g.NavDisableHighlight = false;
     9232        g.NavDisableMouseHover = true;
     9233        apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
     9234        ClosePopupsOverWindow(apply_focus_window, false);
     9235        FocusWindow(apply_focus_window);
     9236        if (apply_focus_window->NavLastIds[0] == 0)
     9237            NavInitWindow(apply_focus_window, false);
     9238
     9239        // If the window only has a menu layer, select it directly
     9240        if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
     9241            g.NavLayer = ImGuiNavLayer_Menu;
     9242    }
     9243    if (apply_focus_window)
     9244        g.NavWindowingTarget = NULL;
     9245
     9246    // Apply menu/layer toggle
     9247    if (apply_toggle_layer && g.NavWindow)
     9248    {
     9249        // Move to parent menu if necessary
     9250        ImGuiWindow* new_nav_window = g.NavWindow;
     9251        while (new_nav_window->ParentWindow
     9252            && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
     9253            && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
     9254            && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
     9255            new_nav_window = new_nav_window->ParentWindow;
     9256        if (new_nav_window != g.NavWindow)
     9257        {
     9258            ImGuiWindow* old_nav_window = g.NavWindow;
     9259            FocusWindow(new_nav_window);
     9260            new_nav_window->NavLastChildNavWindow = old_nav_window;
     9261        }
     9262        g.NavDisableHighlight = false;
     9263        g.NavDisableMouseHover = true;
     9264
     9265        // When entering a regular menu bar with the Alt key, we always reinitialize the navigation ID.
     9266        const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
     9267        NavRestoreLayer(new_nav_layer);
     9268    }
     9269}
     9270
     9271// Window has already passed the IsWindowNavFocusable()
     9272static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
     9273{
     9274    if (window->Flags & ImGuiWindowFlags_Popup)
     9275        return "(Popup)";
     9276    if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
     9277        return "(Main menu bar)";
     9278    return "(Untitled)";
     9279}
     9280
     9281// Overlay displayed when using CTRL+TAB. Called by EndFrame().
     9282void ImGui::NavUpdateWindowingOverlay()
     9283{
     9284    ImGuiContext& g = *GImGui;
     9285    IM_ASSERT(g.NavWindowingTarget != NULL);
     9286
     9287    if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)
     9288        return;
     9289
     9290    if (g.NavWindowingListWindow == NULL)
     9291        g.NavWindowingListWindow = FindWindowByName("###NavWindowingList");
     9292    SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
     9293    SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
     9294    PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
     9295    Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
     9296    for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
     9297    {
     9298        ImGuiWindow* window = g.WindowsFocusOrder[n];
     9299        if (!IsWindowNavFocusable(window))
    115269300            continue;
    11527          for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
    11528          {
    11529             float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
    11530             if (x2 <= x1)
    11531                continue;
    11532             int rounding_corners_flags_cell = 0;
    11533             if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_TopRight; }
    11534             if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImDrawCornerFlags_BotRight; }
    11535             rounding_corners_flags_cell &= rounding_corners_flags;
    11536             window->DrawList->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell);
    11537          }
    11538       }
    11539    }
    11540    else
    11541    {
    11542       window->DrawList->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags);
    11543    }
    11544 }
    11545 
    11546 void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags)
    11547 {
    11548    ImGuiContext& g = *GImGui;
    11549    if ((flags & ImGuiColorEditFlags__InputsMask) == 0)
    11550       flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__InputsMask;
    11551    if ((flags & ImGuiColorEditFlags__DataTypeMask) == 0)
    11552       flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__DataTypeMask;
    11553    if ((flags & ImGuiColorEditFlags__PickerMask) == 0)
    11554       flags |= ImGuiColorEditFlags__OptionsDefault & ImGuiColorEditFlags__PickerMask;
    11555    IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__InputsMask)));   // Check only 1 option is selected
    11556    IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__DataTypeMask))); // Check only 1 option is selected
    11557    IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask)));   // Check only 1 option is selected
    11558    g.ColorEditOptions = flags;
    11559 }
    11560 
    11561 // A little colored square. Return true when clicked.
    11562 // FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip.
    11563 // 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip.
    11564 bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size)
    11565 {
    11566    ImGuiWindow* window = GetCurrentWindow();
    11567    if (window->SkipItems)
    11568       return false;
    11569 
    11570    ImGuiContext& g = *GImGui;
    11571    const ImGuiID id = window->GetID(desc_id);
    11572    float default_size = GetFrameHeight();
    11573    if (size.x == 0.0f)
    11574       size.x = default_size;
    11575    if (size.y == 0.0f)
    11576       size.y = default_size;
    11577    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
    11578    ItemSize(bb, (size.y >= default_size) ? g.Style.FramePadding.y : 0.0f);
    11579    if (!ItemAdd(bb, id))
    11580       return false;
    11581 
    11582    bool hovered, held;
    11583    bool pressed = ButtonBehavior(bb, id, &hovered, &held);
    11584 
    11585    if (flags & ImGuiColorEditFlags_NoAlpha)
    11586       flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf);
    11587 
    11588    ImVec4 col_without_alpha(col.x, col.y, col.z, 1.0f);
    11589    float grid_step = ImMin(size.x, size.y) / 2.99f;
    11590    float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f);
    11591    ImRect bb_inner = bb;
    11592    float off = -0.75f; // The border (using Col_FrameBg) tends to look off when color is near-opaque and rounding is enabled. This offset seemed like a good middle ground to reduce those artifacts.
    11593    bb_inner.Expand(off);
    11594    if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col.w < 1.0f)
    11595    {
    11596       float mid_x = (float)(int)((bb_inner.Min.x + bb_inner.Max.x) * 0.5f + 0.5f);
    11597       RenderColorRectWithAlphaCheckerboard(ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight);
    11598       window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_without_alpha), rounding, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft);
    11599    }
    11600    else
    11601    {
    11602       // Because GetColorU32() multiplies by the global style Alpha and we don't want to display a checkerboard if the source code had no alpha
    11603       ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col : col_without_alpha;
    11604       if (col_source.w < 1.0f)
    11605          RenderColorRectWithAlphaCheckerboard(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding);
    11606       else
    11607          window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding, ImDrawCornerFlags_All);
    11608    }
    11609    RenderNavHighlight(bb, id);
    11610    if (g.Style.FrameBorderSize > 0.0f)
    11611       RenderFrameBorder(bb.Min, bb.Max, rounding);
    11612    else
    11613       window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border
    11614 
    11615                                                                                           // Drag and Drop Source
    11616    if (g.ActiveId == id && BeginDragDropSource()) // NB: The ActiveId test is merely an optional micro-optimization
    11617    {
    11618       if (flags & ImGuiColorEditFlags_NoAlpha)
    11619          SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col, sizeof(float) * 3, ImGuiCond_Once);
    11620       else
    11621          SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col, sizeof(float) * 4, ImGuiCond_Once);
    11622       ColorButton(desc_id, col, flags);
    11623       SameLine();
    11624       TextUnformatted("Color");
    11625       EndDragDropSource();
    11626       hovered = false;
    11627    }
    11628 
    11629    // Tooltip
    11630    if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered)
    11631       ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
    11632 
    11633    return pressed;
    11634 }
    11635 
    11636 bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags)
    11637 {
    11638    return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha);
    11639 }
    11640 
    11641 void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags)
    11642 {
    11643    bool allow_opt_inputs = !(flags & ImGuiColorEditFlags__InputsMask);
    11644    bool allow_opt_datatype = !(flags & ImGuiColorEditFlags__DataTypeMask);
    11645    if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context"))
    11646       return;
    11647    ImGuiContext& g = *GImGui;
    11648    ImGuiColorEditFlags opts = g.ColorEditOptions;
    11649    if (allow_opt_inputs)
    11650    {
    11651       if (RadioButton("RGB", (opts & ImGuiColorEditFlags_RGB) != 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_RGB;
    11652       if (RadioButton("HSV", (opts & ImGuiColorEditFlags_HSV) != 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_HSV;
    11653       if (RadioButton("HEX", (opts & ImGuiColorEditFlags_HEX) != 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_HEX;
    11654    }
    11655    if (allow_opt_datatype)
    11656    {
    11657       if (allow_opt_inputs) Separator();
    11658       if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Uint8;
    11659       if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Float;
    11660    }
    11661 
    11662    if (allow_opt_inputs || allow_opt_datatype)
    11663       Separator();
    11664    if (Button("Copy as..", ImVec2(-1, 0)))
    11665       OpenPopup("Copy");
    11666    if (BeginPopup("Copy"))
    11667    {
    11668       int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
    11669       char buf[64];
    11670       ImFormatString(buf, IM_ARRAYSIZE(buf), "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
    11671       if (Selectable(buf))
    11672          SetClipboardText(buf);
    11673       ImFormatString(buf, IM_ARRAYSIZE(buf), "(%d,%d,%d,%d)", cr, cg, cb, ca);
    11674       if (Selectable(buf))
    11675          SetClipboardText(buf);
    11676       if (flags & ImGuiColorEditFlags_NoAlpha)
    11677          ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X", cr, cg, cb);
    11678       else
    11679          ImFormatString(buf, IM_ARRAYSIZE(buf), "0x%02X%02X%02X%02X", cr, cg, cb, ca);
    11680       if (Selectable(buf))
    11681          SetClipboardText(buf);
    11682       EndPopup();
    11683    }
    11684 
    11685    g.ColorEditOptions = opts;
    11686    EndPopup();
    11687 }
    11688 
    11689 static void ColorPickerOptionsPopup(ImGuiColorEditFlags flags, const float* ref_col)
    11690 {
    11691    bool allow_opt_picker = !(flags & ImGuiColorEditFlags__PickerMask);
    11692    bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar);
    11693    if ((!allow_opt_picker && !allow_opt_alpha_bar) || !ImGui::BeginPopup("context"))
    11694       return;
    11695    ImGuiContext& g = *GImGui;
    11696    if (allow_opt_picker)
    11697    {
    11698       ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (ImGui::GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function
    11699       ImGui::PushItemWidth(picker_size.x);
    11700       for (int picker_type = 0; picker_type < 2; picker_type++)
    11701       {
    11702          // Draw small/thumbnail version of each picker type (over an invisible button for selection)
    11703          if (picker_type > 0) ImGui::Separator();
    11704          ImGui::PushID(picker_type);
    11705          ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | (flags & ImGuiColorEditFlags_NoAlpha);
    11706          if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar;
    11707          if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel;
    11708          ImVec2 backup_pos = ImGui::GetCursorScreenPos();
    11709          if (ImGui::Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup
    11710             g.ColorEditOptions = (g.ColorEditOptions & ~ImGuiColorEditFlags__PickerMask) | (picker_flags & ImGuiColorEditFlags__PickerMask);
    11711          ImGui::SetCursorScreenPos(backup_pos);
    11712          ImVec4 dummy_ref_col;
    11713          memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4));
    11714          ImGui::ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags);
    11715          ImGui::PopID();
    11716       }
    11717       ImGui::PopItemWidth();
    11718    }
    11719    if (allow_opt_alpha_bar)
    11720    {
    11721       if (allow_opt_picker) ImGui::Separator();
    11722       ImGui::CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar);
    11723    }
    11724    ImGui::EndPopup();
    11725 }
    11726 
    11727 // Edit colors components (each component in 0.0f..1.0f range).
    11728 // See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
    11729 // With typical options: Left-click on colored square to open color picker. Right-click to open option menu. CTRL-Click over input fields to edit them and TAB to go to next item.
    11730 bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags)
    11731 {
    11732    ImGuiWindow* window = GetCurrentWindow();
    11733    if (window->SkipItems)
    11734       return false;
    11735 
    11736    ImGuiContext& g = *GImGui;
    11737    const ImGuiStyle& style = g.Style;
    11738    const float square_sz = GetFrameHeight();
    11739    const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
    11740    const float w_items_all = CalcItemWidth() - w_extra;
    11741    const char* label_display_end = FindRenderedTextEnd(label);
    11742 
    11743    const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0;
    11744    const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0;
    11745    const int components = alpha ? 4 : 3;
    11746    const ImGuiColorEditFlags flags_untouched = flags;
    11747 
    11748    BeginGroup();
    11749    PushID(label);
    11750 
    11751    // If we're not showing any slider there's no point in doing any HSV conversions
    11752    if (flags & ImGuiColorEditFlags_NoInputs)
    11753       flags = (flags & (~ImGuiColorEditFlags__InputsMask)) | ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_NoOptions;
    11754 
    11755    // Context menu: display and modify options (before defaults are applied)
    11756    if (!(flags & ImGuiColorEditFlags_NoOptions))
    11757       ColorEditOptionsPopup(col, flags);
    11758 
    11759    // Read stored options
    11760    if (!(flags & ImGuiColorEditFlags__InputsMask))
    11761       flags |= (g.ColorEditOptions & ImGuiColorEditFlags__InputsMask);
    11762    if (!(flags & ImGuiColorEditFlags__DataTypeMask))
    11763       flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DataTypeMask);
    11764    if (!(flags & ImGuiColorEditFlags__PickerMask))
    11765       flags |= (g.ColorEditOptions & ImGuiColorEditFlags__PickerMask);
    11766    flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask));
    11767 
    11768    // Convert to the formats we need
    11769    float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f };
    11770    if (flags & ImGuiColorEditFlags_HSV)
    11771       ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
    11772    int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) };
    11773 
    11774    bool value_changed = false;
    11775    bool value_changed_as_float = false;
    11776 
    11777    if ((flags & (ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_HSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
    11778    {
    11779       // RGB/HSV 0..255 Sliders
    11780       const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));
    11781       const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));
    11782 
    11783       const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
    11784       const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
    11785       const char* fmt_table_int[3][4] =
    11786       {
    11787          { "%3.0f",   "%3.0f",   "%3.0f",   "%3.0f" }, // Short display
    11788       { "R:%3.0f", "G:%3.0f", "B:%3.0f", "A:%3.0f" }, // Long display for RGBA
    11789       { "H:%3.0f", "S:%3.0f", "V:%3.0f", "A:%3.0f" }  // Long display for HSVA
    11790       };
    11791       const char* fmt_table_float[3][4] =
    11792       {
    11793          { "%0.3f",   "%0.3f",   "%0.3f",   "%0.3f" }, // Short display
    11794       { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA
    11795       { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" }  // Long display for HSVA
    11796       };
    11797       const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_HSV) ? 2 : 1;
    11798 
    11799       PushItemWidth(w_item_one);
    11800       for (int n = 0; n < components; n++)
    11801       {
    11802          if (n > 0)
    11803             SameLine(0, style.ItemInnerSpacing.x);
    11804          if (n + 1 == components)
    11805             PushItemWidth(w_item_last);
    11806          if (flags & ImGuiColorEditFlags_Float)
    11807             value_changed = value_changed_as_float = value_changed | DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
    11808          else
    11809             value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
    11810          if (!(flags & ImGuiColorEditFlags_NoOptions))
    11811             OpenPopupOnItemClick("context");
    11812       }
    11813       PopItemWidth();
    11814       PopItemWidth();
    11815    }
    11816    else if ((flags & ImGuiColorEditFlags_HEX) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
    11817    {
    11818       // RGB Hexadecimal Input
    11819       char buf[64];
    11820       if (alpha)
    11821          ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255));
    11822       else
    11823          ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255));
    11824       PushItemWidth(w_items_all);
    11825       if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase))
    11826       {
    11827          value_changed = true;
    11828          char* p = buf;
    11829          while (*p == '#' || ImCharIsSpace((unsigned int)*p))
    11830             p++;
    11831          i[0] = i[1] = i[2] = i[3] = 0;
    11832          if (alpha)
    11833             sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned)
    11834          else
    11835             sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]);
    11836       }
    11837       if (!(flags & ImGuiColorEditFlags_NoOptions))
    11838          OpenPopupOnItemClick("context");
    11839       PopItemWidth();
    11840    }
    11841 
    11842    ImGuiWindow* picker_active_window = NULL;
    11843    if (!(flags & ImGuiColorEditFlags_NoSmallPreview))
    11844    {
    11845       if (!(flags & ImGuiColorEditFlags_NoInputs))
    11846          SameLine(0, style.ItemInnerSpacing.x);
    11847 
    11848       const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f);
    11849       if (ColorButton("##ColorButton", col_v4, flags))
    11850       {
    11851          if (!(flags & ImGuiColorEditFlags_NoPicker))
    11852          {
    11853             // Store current color and open a picker
    11854             g.ColorPickerRef = col_v4;
    11855             OpenPopup("picker");
    11856             SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1, style.ItemSpacing.y));
    11857          }
    11858       }
    11859       if (!(flags & ImGuiColorEditFlags_NoOptions))
    11860          OpenPopupOnItemClick("context");
    11861 
    11862       if (BeginPopup("picker"))
    11863       {
    11864          picker_active_window = g.CurrentWindow;
    11865          if (label != label_display_end)
    11866          {
    11867             TextUnformatted(label, label_display_end);
    11868             Separator();
    11869          }
    11870          ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
    11871          ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
    11872          PushItemWidth(square_sz * 12.0f); // Use 256 + bar sizes?
    11873          value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x);
    11874          PopItemWidth();
    11875          EndPopup();
    11876       }
    11877    }
    11878 
    11879    if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
    11880    {
    11881       SameLine(0, style.ItemInnerSpacing.x);
    11882       TextUnformatted(label, label_display_end);
    11883    }
    11884 
    11885    // Convert back
    11886    if (picker_active_window == NULL)
    11887    {
    11888       if (!value_changed_as_float)
    11889          for (int n = 0; n < 4; n++)
    11890             f[n] = i[n] / 255.0f;
    11891       if (flags & ImGuiColorEditFlags_HSV)
    11892          ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
    11893       if (value_changed)
    11894       {
    11895          col[0] = f[0];
    11896          col[1] = f[1];
    11897          col[2] = f[2];
    11898          if (alpha)
    11899             col[3] = f[3];
    11900       }
    11901    }
    11902 
    11903    PopID();
    11904    EndGroup();
    11905 
    11906    // Drag and Drop Target
    11907    if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) && BeginDragDropTarget()) // NB: The flag test is merely an optional micro-optimization, BeginDragDropTarget() does the same test.
    11908    {
    11909       if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
    11910       {
    11911          memcpy((float*)col, payload->Data, sizeof(float) * 3);
    11912          value_changed = true;
    11913       }
    11914       if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
    11915       {
    11916          memcpy((float*)col, payload->Data, sizeof(float) * components);
    11917          value_changed = true;
    11918       }
    11919       EndDragDropTarget();
    11920    }
    11921 
    11922    // When picker is being actively used, use its active id so IsItemActive() will function on ColorEdit4().
    11923    if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window)
    11924       window->DC.LastItemId = g.ActiveId;
    11925 
    11926    return value_changed;
    11927 }
    11928 
    11929 bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags)
    11930 {
    11931    float col4[4] = { col[0], col[1], col[2], 1.0f };
    11932    if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha))
    11933       return false;
    11934    col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2];
    11935    return true;
    11936 }
    11937 
    11938 // 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
    11939 static void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
    11940 {
    11941    switch (direction)
    11942    {
    11943    case ImGuiDir_Left:  draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), pos, col); return;
    11944    case ImGuiDir_Right: draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), pos, col); return;
    11945    case ImGuiDir_Up:    draw_list->AddTriangleFilled(ImVec2(pos.x + half_sz.x, pos.y + half_sz.y), ImVec2(pos.x - half_sz.x, pos.y + half_sz.y), pos, col); return;
    11946    case ImGuiDir_Down:  draw_list->AddTriangleFilled(ImVec2(pos.x - half_sz.x, pos.y - half_sz.y), ImVec2(pos.x + half_sz.x, pos.y - half_sz.y), pos, col); return;
    11947    case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings
    11948    }
    11949 }
    11950 
    11951 static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w)
    11952 {
    11953    RenderArrow(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32_BLACK);
    11954    RenderArrow(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32_WHITE);
    11955    RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32_BLACK);
    11956    RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32_WHITE);
    11957 }
    11958 
    11959 // ColorPicker
    11960 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
    11961 // FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..)
    11962 bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col)
    11963 {
    11964    ImGuiContext& g = *GImGui;
    11965    ImGuiWindow* window = GetCurrentWindow();
    11966    ImDrawList* draw_list = window->DrawList;
    11967 
    11968    ImGuiStyle& style = g.Style;
    11969    ImGuiIO& io = g.IO;
    11970 
    11971    PushID(label);
    11972    BeginGroup();
    11973 
    11974    if (!(flags & ImGuiColorEditFlags_NoSidePreview))
    11975       flags |= ImGuiColorEditFlags_NoSmallPreview;
    11976 
    11977    // Context menu: display and store options.
    11978    if (!(flags & ImGuiColorEditFlags_NoOptions))
    11979       ColorPickerOptionsPopup(flags, col);
    11980 
    11981    // Read stored options
    11982    if (!(flags & ImGuiColorEditFlags__PickerMask))
    11983       flags |= ((g.ColorEditOptions & ImGuiColorEditFlags__PickerMask) ? g.ColorEditOptions : ImGuiColorEditFlags__OptionsDefault) & ImGuiColorEditFlags__PickerMask;
    11984    IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check that only 1 is selected
    11985    if (!(flags & ImGuiColorEditFlags_NoOptions))
    11986       flags |= (g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar);
    11987 
    11988    // Setup
    11989    int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4;
    11990    bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha);
    11991    ImVec2 picker_pos = window->DC.CursorPos;
    11992    float square_sz = GetFrameHeight();
    11993    float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars
    11994    float sv_picker_size = ImMax(bars_width * 1, CalcItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box
    11995    float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
    11996    float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
    11997    float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f);
    11998 
    11999    float backup_initial_col[4];
    12000    memcpy(backup_initial_col, col, components * sizeof(float));
    12001 
    12002    float wheel_thickness = sv_picker_size * 0.08f;
    12003    float wheel_r_outer = sv_picker_size * 0.50f;
    12004    float wheel_r_inner = wheel_r_outer - wheel_thickness;
    12005    ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f);
    12006 
    12007    // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic.
    12008    float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f);
    12009    ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point.
    12010    ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point.
    12011    ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point.
    12012 
    12013    float H, S, V;
    12014    ColorConvertRGBtoHSV(col[0], col[1], col[2], H, S, V);
    12015 
    12016    bool value_changed = false, value_changed_h = false, value_changed_sv = false;
    12017 
    12018    PushItemFlag(ImGuiItemFlags_NoNav, true);
    12019    if (flags & ImGuiColorEditFlags_PickerHueWheel)
    12020    {
    12021       // Hue wheel + SV triangle logic
    12022       InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size));
    12023       if (IsItemActive())
    12024       {
    12025          ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center;
    12026          ImVec2 current_off = g.IO.MousePos - wheel_center;
    12027          float initial_dist2 = ImLengthSqr(initial_off);
    12028          if (initial_dist2 >= (wheel_r_inner - 1)*(wheel_r_inner - 1) && initial_dist2 <= (wheel_r_outer + 1)*(wheel_r_outer + 1))
    12029          {
    12030             // Interactive with Hue wheel
    12031             H = atan2f(current_off.y, current_off.x) / IM_PI * 0.5f;
    12032             if (H < 0.0f)
    12033                H += 1.0f;
    12034             value_changed = value_changed_h = true;
    12035          }
    12036          float cos_hue_angle = cosf(-H * 2.0f * IM_PI);
    12037          float sin_hue_angle = sinf(-H * 2.0f * IM_PI);
    12038          if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle)))
    12039          {
    12040             // Interacting with SV triangle
    12041             ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle);
    12042             if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated))
    12043                current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated);
    12044             float uu, vv, ww;
    12045             ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww);
    12046             V = ImClamp(1.0f - vv, 0.0001f, 1.0f);
    12047             S = ImClamp(uu / V, 0.0001f, 1.0f);
    12048             value_changed = value_changed_sv = true;
    12049          }
    12050       }
    12051       if (!(flags & ImGuiColorEditFlags_NoOptions))
    12052          OpenPopupOnItemClick("context");
    12053    }
    12054    else if (flags & ImGuiColorEditFlags_PickerHueBar)
    12055    {
    12056       // SV rectangle logic
    12057       InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size));
    12058       if (IsItemActive())
    12059       {
    12060          S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1));
    12061          V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));
    12062          value_changed = value_changed_sv = true;
    12063       }
    12064       if (!(flags & ImGuiColorEditFlags_NoOptions))
    12065          OpenPopupOnItemClick("context");
    12066 
    12067       // Hue bar logic
    12068       SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y));
    12069       InvisibleButton("hue", ImVec2(bars_width, sv_picker_size));
    12070       if (IsItemActive())
    12071       {
    12072          H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));
    12073          value_changed = value_changed_h = true;
    12074       }
    12075    }
    12076 
    12077    // Alpha bar logic
    12078    if (alpha_bar)
    12079    {
    12080       SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y));
    12081       InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size));
    12082       if (IsItemActive())
    12083       {
    12084          col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));
    12085          value_changed = true;
    12086       }
    12087    }
    12088    PopItemFlag(); // ImGuiItemFlags_NoNav
    12089 
    12090    if (!(flags & ImGuiColorEditFlags_NoSidePreview))
    12091    {
    12092       SameLine(0, style.ItemInnerSpacing.x);
    12093       BeginGroup();
    12094    }
    12095 
    12096    if (!(flags & ImGuiColorEditFlags_NoLabel))
    12097    {
    12098       const char* label_display_end = FindRenderedTextEnd(label);
    12099       if (label != label_display_end)
    12100       {
    12101          if ((flags & ImGuiColorEditFlags_NoSidePreview))
    12102             SameLine(0, style.ItemInnerSpacing.x);
    12103          TextUnformatted(label, label_display_end);
    12104       }
    12105    }
    12106 
    12107    if (!(flags & ImGuiColorEditFlags_NoSidePreview))
    12108    {
    12109       PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
    12110       ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
    12111       if ((flags & ImGuiColorEditFlags_NoLabel))
    12112          Text("Current");
    12113       ColorButton("##current", col_v4, (flags & (ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip)), ImVec2(square_sz * 3, square_sz * 2));
    12114       if (ref_col != NULL)
    12115       {
    12116          Text("Original");
    12117          ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]);
    12118          if (ColorButton("##original", ref_col_v4, (flags & (ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip)), ImVec2(square_sz * 3, square_sz * 2)))
    12119          {
    12120             memcpy(col, ref_col, components * sizeof(float));
    12121             value_changed = true;
    12122          }
    12123       }
    12124       PopItemFlag();
    12125       EndGroup();
    12126    }
    12127 
    12128    // Convert back color to RGB
    12129    if (value_changed_h || value_changed_sv)
    12130       ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10 * 1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]);
    12131 
    12132    // R,G,B and H,S,V slider color editor
    12133    if ((flags & ImGuiColorEditFlags_NoInputs) == 0)
    12134    {
    12135       PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x);
    12136       ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf;
    12137       ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker;
    12138       if (flags & ImGuiColorEditFlags_RGB || (flags & ImGuiColorEditFlags__InputsMask) == 0)
    12139          value_changed |= ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_RGB);
    12140       if (flags & ImGuiColorEditFlags_HSV || (flags & ImGuiColorEditFlags__InputsMask) == 0)
    12141          value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_HSV);
    12142       if (flags & ImGuiColorEditFlags_HEX || (flags & ImGuiColorEditFlags__InputsMask) == 0)
    12143          value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_HEX);
    12144       PopItemWidth();
    12145    }
    12146 
    12147    // Try to cancel hue wrap (after ColorEdit), if any
    12148    if (value_changed)
    12149    {
    12150       float new_H, new_S, new_V;
    12151       ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V);
    12152       if (new_H <= 0 && H > 0)
    12153       {
    12154          if (new_V <= 0 && V != new_V)
    12155             ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]);
    12156          else if (new_S <= 0)
    12157             ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]);
    12158       }
    12159    }
    12160 
    12161    ImVec4 hue_color_f(1, 1, 1, 1); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
    12162    ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);
    12163    ImU32 col32_no_alpha = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 1.0f));
    12164 
    12165    const ImU32 hue_colors[6 + 1] = { IM_COL32(255,0,0,255), IM_COL32(255,255,0,255), IM_COL32(0,255,0,255), IM_COL32(0,255,255,255), IM_COL32(0,0,255,255), IM_COL32(255,0,255,255), IM_COL32(255,0,0,255) };
    12166    ImVec2 sv_cursor_pos;
    12167 
    12168    if (flags & ImGuiColorEditFlags_PickerHueWheel)
    12169    {
    12170       // Render Hue Wheel
    12171       const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).
    12172       const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12);
    12173       for (int n = 0; n < 6; n++)
    12174       {
    12175          const float a0 = (n) / 6.0f * 2.0f * IM_PI - aeps;
    12176          const float a1 = (n + 1.0f) / 6.0f * 2.0f * IM_PI + aeps;
    12177          const int vert_start_idx = draw_list->VtxBuffer.Size;
    12178          draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc);
    12179          draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness);
    12180          const int vert_end_idx = draw_list->VtxBuffer.Size;
    12181 
    12182          // Paint colors over existing vertices
    12183          ImVec2 gradient_p0(wheel_center.x + cosf(a0) * wheel_r_inner, wheel_center.y + sinf(a0) * wheel_r_inner);
    12184          ImVec2 gradient_p1(wheel_center.x + cosf(a1) * wheel_r_inner, wheel_center.y + sinf(a1) * wheel_r_inner);
    12185          ShadeVertsLinearColorGradientKeepAlpha(draw_list->VtxBuffer.Data + vert_start_idx, draw_list->VtxBuffer.Data + vert_end_idx, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n + 1]);
    12186       }
    12187 
    12188       // Render Cursor + preview on Hue Wheel
    12189       float cos_hue_angle = cosf(H * 2.0f * IM_PI);
    12190       float sin_hue_angle = sinf(H * 2.0f * IM_PI);
    12191       ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer)*0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer)*0.5f);
    12192       float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;
    12193       int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32);
    12194       draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);
    12195       draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, IM_COL32(128, 128, 128, 255), hue_cursor_segments);
    12196       draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments);
    12197 
    12198       // Render SV triangle (rotated according to hue)
    12199       ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);
    12200       ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle);
    12201       ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle);
    12202       ImVec2 uv_white = GetFontTexUvWhitePixel();
    12203       draw_list->PrimReserve(6, 6);
    12204       draw_list->PrimVtx(tra, uv_white, hue_color32);
    12205       draw_list->PrimVtx(trb, uv_white, hue_color32);
    12206       draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE);
    12207       draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS);
    12208       draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK);
    12209       draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS);
    12210       draw_list->AddTriangle(tra, trb, trc, IM_COL32(128, 128, 128, 255), 1.5f);
    12211       sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));
    12212    }
    12213    else if (flags & ImGuiColorEditFlags_PickerHueBar)
    12214    {
    12215       // Render SV Square
    12216       draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE);
    12217       draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), IM_COL32_BLACK_TRANS, IM_COL32_BLACK_TRANS, IM_COL32_BLACK, IM_COL32_BLACK);
    12218       RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f);
    12219       sv_cursor_pos.x = ImClamp((float)(int)(picker_pos.x + ImSaturate(S)     * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much
    12220       sv_cursor_pos.y = ImClamp((float)(int)(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);
    12221 
    12222       // Render Hue Bar
    12223       for (int i = 0; i < 6; ++i)
    12224          draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), hue_colors[i], hue_colors[i], hue_colors[i + 1], hue_colors[i + 1]);
    12225       float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f);
    12226       RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);
    12227       RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
    12228    }
    12229 
    12230    // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range)
    12231    float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f;
    12232    draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, col32_no_alpha, 12);
    12233    draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, IM_COL32(128, 128, 128, 255), 12);
    12234    draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, IM_COL32_WHITE, 12);
    12235 
    12236    // Render alpha bar
    12237    if (alpha_bar)
    12238    {
    12239       float alpha = ImSaturate(col[3]);
    12240       ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);
    12241       RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, IM_COL32(0, 0, 0, 0), bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
    12242       draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, col32_no_alpha, col32_no_alpha, col32_no_alpha & ~IM_COL32_A_MASK, col32_no_alpha & ~IM_COL32_A_MASK);
    12243       float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f);
    12244       RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);
    12245       RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
    12246    }
    12247 
    12248    EndGroup();
    12249    PopID();
    12250 
    12251    return value_changed && memcmp(backup_initial_col, col, components * sizeof(float));
    12252 }
    12253 
    12254 // Horizontal separating line.
    12255 void ImGui::Separator()
    12256 {
    12257    ImGuiWindow* window = GetCurrentWindow();
    12258    if (window->SkipItems)
    12259       return;
    12260    ImGuiContext& g = *GImGui;
    12261 
    12262    ImGuiSeparatorFlags flags = 0;
    12263    if ((flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)) == 0)
    12264       flags |= (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;
    12265    IM_ASSERT(ImIsPowerOfTwo((int)(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))));   // Check that only 1 option is selected
    12266    if (flags & ImGuiSeparatorFlags_Vertical)
    12267    {
    12268       VerticalSeparator();
    12269       return;
    12270    }
    12271 
    12272    // Horizontal Separator
    12273    if (window->DC.ColumnsSet)
    12274       PopClipRect();
    12275 
    12276    float x1 = window->Pos.x;
    12277    float x2 = window->Pos.x + window->Size.x;
    12278    if (!window->DC.GroupStack.empty())
    12279       x1 += window->DC.IndentX;
    12280 
    12281    const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + 1.0f));
    12282    ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit, we don't provide height to not alter layout.
    12283    if (!ItemAdd(bb, 0))
    12284    {
    12285       if (window->DC.ColumnsSet)
    12286          PushColumnClipRect();
    12287       return;
    12288    }
    12289 
    12290    window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator));
    12291 
    12292    if (g.LogEnabled)
    12293       LogRenderedText(NULL, IM_NEWLINE "--------------------------------");
    12294 
    12295    if (window->DC.ColumnsSet)
    12296    {
    12297       PushColumnClipRect();
    12298       window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y;
    12299    }
    12300 }
    12301 
    12302 void ImGui::VerticalSeparator()
    12303 {
    12304    ImGuiWindow* window = GetCurrentWindow();
    12305    if (window->SkipItems)
    12306       return;
    12307    ImGuiContext& g = *GImGui;
    12308 
    12309    float y1 = window->DC.CursorPos.y;
    12310    float y2 = window->DC.CursorPos.y + window->DC.CurrentLineHeight;
    12311    const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2));
    12312    ItemSize(ImVec2(bb.GetWidth(), 0.0f));
    12313    if (!ItemAdd(bb, 0))
    12314       return;
    12315 
    12316    window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator));
    12317    if (g.LogEnabled)
    12318       LogText(" |");
    12319 }
    12320 
    12321 bool ImGui::SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend)
    12322 {
    12323    ImGuiContext& g = *GImGui;
    12324    ImGuiWindow* window = g.CurrentWindow;
    12325 
    12326    const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
    12327    window->DC.ItemFlags |= ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus;
    12328    bool item_add = ItemAdd(bb, id);
    12329    window->DC.ItemFlags = item_flags_backup;
    12330    if (!item_add)
    12331       return false;
    12332 
    12333    bool hovered, held;
    12334    ImRect bb_interact = bb;
    12335    bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f));
    12336    ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap);
    12337    if (g.ActiveId != id)
    12338       SetItemAllowOverlap();
    12339 
    12340    if (held || (g.HoveredId == id && g.HoveredIdPreviousFrame == id))
    12341       SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW);
    12342 
    12343    ImRect bb_render = bb;
    12344    if (held)
    12345    {
    12346       ImVec2 mouse_delta_2d = g.IO.MousePos - g.ActiveIdClickOffset - bb_interact.Min;
    12347       float mouse_delta = (axis == ImGuiAxis_Y) ? mouse_delta_2d.y : mouse_delta_2d.x;
    12348 
    12349       // Minimum pane size
    12350       if (mouse_delta < min_size1 - *size1)
    12351          mouse_delta = min_size1 - *size1;
    12352       if (mouse_delta > *size2 - min_size2)
    12353          mouse_delta = *size2 - min_size2;
    12354 
    12355       // Apply resize
    12356       *size1 += mouse_delta;
    12357       *size2 -= mouse_delta;
    12358       bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta));
    12359    }
    12360 
    12361    // Render
    12362    const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
    12363    window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, g.Style.FrameRounding);
    12364 
    12365    return held;
    12366 }
    12367 
    12368 void ImGui::Spacing()
    12369 {
    12370    ImGuiWindow* window = GetCurrentWindow();
    12371    if (window->SkipItems)
    12372       return;
    12373    ItemSize(ImVec2(0, 0));
    12374 }
    12375 
    12376 void ImGui::Dummy(const ImVec2& size)
    12377 {
    12378    ImGuiWindow* window = GetCurrentWindow();
    12379    if (window->SkipItems)
    12380       return;
    12381 
    12382    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
    12383    ItemSize(bb);
    12384    ItemAdd(bb, 0);
    12385 }
    12386 
    12387 bool ImGui::IsRectVisible(const ImVec2& size)
    12388 {
    12389    ImGuiWindow* window = GetCurrentWindowRead();
    12390    return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
    12391 }
    12392 
    12393 bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
    12394 {
    12395    ImGuiWindow* window = GetCurrentWindowRead();
    12396    return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
    12397 }
    12398 
    12399 // 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.)
    12400 void ImGui::BeginGroup()
    12401 {
    12402    ImGuiWindow* window = GetCurrentWindow();
    12403 
    12404    window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
    12405    ImGuiGroupData& group_data = window->DC.GroupStack.back();
    12406    group_data.BackupCursorPos = window->DC.CursorPos;
    12407    group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
    12408    group_data.BackupIndentX = window->DC.IndentX;
    12409    group_data.BackupGroupOffsetX = window->DC.GroupOffsetX;
    12410    group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight;
    12411    group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset;
    12412    group_data.BackupLogLinePosY = window->DC.LogLinePosY;
    12413    group_data.BackupActiveIdIsAlive = GImGui->ActiveIdIsAlive;
    12414    group_data.AdvanceCursor = true;
    12415 
    12416    window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX;
    12417    window->DC.IndentX = window->DC.GroupOffsetX;
    12418    window->DC.CursorMaxPos = window->DC.CursorPos;
    12419    window->DC.CurrentLineHeight = 0.0f;
    12420    window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
    12421 }
    12422 
    12423 void ImGui::EndGroup()
    12424 {
    12425    ImGuiContext& g = *GImGui;
    12426    ImGuiWindow* window = GetCurrentWindow();
    12427 
    12428    IM_ASSERT(!window->DC.GroupStack.empty());    // Mismatched BeginGroup()/EndGroup() calls
    12429 
    12430    ImGuiGroupData& group_data = window->DC.GroupStack.back();
    12431 
    12432    ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos);
    12433    group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
    12434 
    12435    window->DC.CursorPos = group_data.BackupCursorPos;
    12436    window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
    12437    window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight;
    12438    window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
    12439    window->DC.IndentX = group_data.BackupIndentX;
    12440    window->DC.GroupOffsetX = group_data.BackupGroupOffsetX;
    12441    window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
    12442 
    12443    if (group_data.AdvanceCursor)
    12444    {
    12445       window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset);      // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
    12446       ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset);
    12447       ItemAdd(group_bb, 0);
    12448    }
    12449 
    12450    // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive() will be functional on the entire group.
    12451    // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but if you search for LastItemId you'll notice it is only used in that context.
    12452    const bool active_id_within_group = (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow);
    12453    if (active_id_within_group)
    12454       window->DC.LastItemId = g.ActiveId;
    12455    window->DC.LastItemRect = group_bb;
    12456 
    12457    window->DC.GroupStack.pop_back();
    12458 
    12459    //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255));   // [Debug]
    12460 }
    12461 
    12462 // Gets back to previous line and continue with horizontal layout
    12463 //      pos_x == 0      : follow right after previous item
    12464 //      pos_x != 0      : align to specified x position (relative to window/group left)
    12465 //      spacing_w < 0   : use default spacing if pos_x == 0, no spacing if pos_x != 0
    12466 //      spacing_w >= 0  : enforce spacing amount
    12467 void ImGui::SameLine(float pos_x, float spacing_w)
    12468 {
    12469    ImGuiWindow* window = GetCurrentWindow();
    12470    if (window->SkipItems)
    12471       return;
    12472 
    12473    ImGuiContext& g = *GImGui;
    12474    if (pos_x != 0.0f)
    12475    {
    12476       if (spacing_w < 0.0f) spacing_w = 0.0f;
    12477       window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffsetX + window->DC.ColumnsOffsetX;
    12478       window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
    12479    }
    12480    else
    12481    {
    12482       if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
    12483       window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
    12484       window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
    12485    }
    12486    window->DC.CurrentLineHeight = window->DC.PrevLineHeight;
    12487    window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
    12488 }
    12489 
    12490 void ImGui::NewLine()
    12491 {
    12492    ImGuiWindow* window = GetCurrentWindow();
    12493    if (window->SkipItems)
    12494       return;
    12495 
    12496    ImGuiContext& g = *GImGui;
    12497    const ImGuiLayoutType backup_layout_type = window->DC.LayoutType;
    12498    window->DC.LayoutType = ImGuiLayoutType_Vertical;
    12499    if (window->DC.CurrentLineHeight > 0.0f)     // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height.
    12500       ItemSize(ImVec2(0, 0));
    12501    else
    12502       ItemSize(ImVec2(0.0f, g.FontSize));
    12503    window->DC.LayoutType = backup_layout_type;
    12504 }
    12505 
    12506 void ImGui::NextColumn()
    12507 {
    12508    ImGuiWindow* window = GetCurrentWindow();
    12509    if (window->SkipItems || window->DC.ColumnsSet == NULL)
    12510       return;
    12511 
    12512    ImGuiContext& g = *GImGui;
    12513    PopItemWidth();
    12514    PopClipRect();
    12515 
    12516    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
    12517    columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
    12518    if (++columns->Current < columns->Count)
    12519    {
    12520       // Columns 1+ cancel out IndentX
    12521       window->DC.ColumnsOffsetX = GetColumnOffset(columns->Current) - window->DC.IndentX + g.Style.ItemSpacing.x;
    12522       window->DrawList->ChannelsSetCurrent(columns->Current);
    12523    }
    12524    else
    12525    {
    12526       window->DC.ColumnsOffsetX = 0.0f;
    12527       window->DrawList->ChannelsSetCurrent(0);
    12528       columns->Current = 0;
    12529       columns->LineMinY = columns->LineMaxY;
    12530    }
    12531    window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
    12532    window->DC.CursorPos.y = columns->LineMinY;
    12533    window->DC.CurrentLineHeight = 0.0f;
    12534    window->DC.CurrentLineTextBaseOffset = 0.0f;
    12535 
    12536    PushColumnClipRect();
    12537    PushItemWidth(GetColumnWidth() * 0.65f);  // FIXME: Move on columns setup
    12538 }
    12539 
    12540 int ImGui::GetColumnIndex()
    12541 {
    12542    ImGuiWindow* window = GetCurrentWindowRead();
    12543    return window->DC.ColumnsSet ? window->DC.ColumnsSet->Current : 0;
    12544 }
    12545 
    12546 int ImGui::GetColumnsCount()
    12547 {
    12548    ImGuiWindow* window = GetCurrentWindowRead();
    12549    return window->DC.ColumnsSet ? window->DC.ColumnsSet->Count : 1;
    12550 }
    12551 
    12552 static float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_norm)
    12553 {
    12554    return offset_norm * (columns->MaxX - columns->MinX);
    12555 }
    12556 
    12557 static float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset)
    12558 {
    12559    return offset / (columns->MaxX - columns->MinX);
    12560 }
    12561 
    12562 static inline float GetColumnsRectHalfWidth() { return 4.0f; }
    12563 
    12564 static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index)
    12565 {
    12566    // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
    12567    // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
    12568    ImGuiContext& g = *GImGui;
    12569    ImGuiWindow* window = g.CurrentWindow;
    12570    IM_ASSERT(column_index > 0); // We are not supposed to drag column 0.
    12571    IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
    12572 
    12573    float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x;
    12574    x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
    12575    if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
    12576       x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
    12577 
    12578    return x;
    12579 }
    12580 
    12581 float ImGui::GetColumnOffset(int column_index)
    12582 {
    12583    ImGuiWindow* window = GetCurrentWindowRead();
    12584    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
    12585    IM_ASSERT(columns != NULL);
    12586 
    12587    if (column_index < 0)
    12588       column_index = columns->Current;
    12589    IM_ASSERT(column_index < columns->Columns.Size);
    12590 
    12591    const float t = columns->Columns[column_index].OffsetNorm;
    12592    const float x_offset = ImLerp(columns->MinX, columns->MaxX, t);
    12593    return x_offset;
    12594 }
    12595 
    12596 static float GetColumnWidthEx(ImGuiColumnsSet* columns, int column_index, bool before_resize = false)
    12597 {
    12598    if (column_index < 0)
    12599       column_index = columns->Current;
    12600 
    12601    float offset_norm;
    12602    if (before_resize)
    12603       offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
    12604    else
    12605       offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
    12606    return OffsetNormToPixels(columns, offset_norm);
    12607 }
    12608 
    12609 float ImGui::GetColumnWidth(int column_index)
    12610 {
    12611    ImGuiWindow* window = GetCurrentWindowRead();
    12612    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
    12613    IM_ASSERT(columns != NULL);
    12614 
    12615    if (column_index < 0)
    12616       column_index = columns->Current;
    12617    return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
    12618 }
    12619 
    12620 void ImGui::SetColumnOffset(int column_index, float offset)
    12621 {
    12622    ImGuiContext& g = *GImGui;
    12623    ImGuiWindow* window = g.CurrentWindow;
    12624    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
    12625    IM_ASSERT(columns != NULL);
    12626 
    12627    if (column_index < 0)
    12628       column_index = columns->Current;
    12629    IM_ASSERT(column_index < columns->Columns.Size);
    12630 
    12631    const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count - 1);
    12632    const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
    12633 
    12634    if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
    12635       offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
    12636    columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX);
    12637 
    12638    if (preserve_width)
    12639       SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
    12640 }
    12641 
    12642 void ImGui::SetColumnWidth(int column_index, float width)
    12643 {
    12644    ImGuiWindow* window = GetCurrentWindowRead();
    12645    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
    12646    IM_ASSERT(columns != NULL);
    12647 
    12648    if (column_index < 0)
    12649       column_index = columns->Current;
    12650    SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
    12651 }
    12652 
    12653 void ImGui::PushColumnClipRect(int column_index)
    12654 {
    12655    ImGuiWindow* window = GetCurrentWindowRead();
    12656    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
    12657    if (column_index < 0)
    12658       column_index = columns->Current;
    12659 
    12660    PushClipRect(columns->Columns[column_index].ClipRect.Min, columns->Columns[column_index].ClipRect.Max, false);
    12661 }
    12662 
    12663 static ImGuiColumnsSet* FindOrAddColumnsSet(ImGuiWindow* window, ImGuiID id)
    12664 {
    12665    for (int n = 0; n < window->ColumnsStorage.Size; n++)
    12666       if (window->ColumnsStorage[n].ID == id)
    12667          return &window->ColumnsStorage[n];
    12668 
    12669    window->ColumnsStorage.push_back(ImGuiColumnsSet());
    12670    ImGuiColumnsSet* columns = &window->ColumnsStorage.back();
    12671    columns->ID = id;
    12672    return columns;
    12673 }
    12674 
    12675 void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
    12676 {
    12677    ImGuiContext& g = *GImGui;
    12678    ImGuiWindow* window = GetCurrentWindow();
    12679 
    12680    IM_ASSERT(columns_count > 1);
    12681    IM_ASSERT(window->DC.ColumnsSet == NULL); // Nested columns are currently not supported
    12682 
    12683                                              // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
    12684                                              // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
    12685    PushID(0x11223347 + (str_id ? 0 : columns_count));
    12686    ImGuiID id = window->GetID(str_id ? str_id : "columns");
    12687    PopID();
    12688 
    12689    // Acquire storage for the columns set
    12690    ImGuiColumnsSet* columns = FindOrAddColumnsSet(window, id);
    12691    IM_ASSERT(columns->ID == id);
    12692    columns->Current = 0;
    12693    columns->Count = columns_count;
    12694    columns->Flags = flags;
    12695    window->DC.ColumnsSet = columns;
    12696 
    12697    // Set state for first column
    12698    const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x);
    12699    columns->MinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range
    12700    columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f);
    12701    columns->StartPosY = window->DC.CursorPos.y;
    12702    columns->StartMaxPosX = window->DC.CursorMaxPos.x;
    12703    columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
    12704    window->DC.ColumnsOffsetX = 0.0f;
    12705    window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
    12706 
    12707    // Clear data if columns count changed
    12708    if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
    12709       columns->Columns.resize(0);
    12710 
    12711    // Initialize defaults
    12712    columns->IsFirstFrame = (columns->Columns.Size == 0);
    12713    if (columns->Columns.Size == 0)
    12714    {
    12715       columns->Columns.reserve(columns_count + 1);
    12716       for (int n = 0; n < columns_count + 1; n++)
    12717       {
    12718          ImGuiColumnData column;
    12719          column.OffsetNorm = n / (float)columns_count;
    12720          columns->Columns.push_back(column);
    12721       }
    12722    }
    12723 
    12724    for (int n = 0; n < columns_count; n++)
    12725    {
    12726       // Compute clipping rectangle
    12727       ImGuiColumnData* column = &columns->Columns[n];
    12728       float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f);
    12729       float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
    12730       column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
    12731       column->ClipRect.ClipWith(window->ClipRect);
    12732    }
    12733 
    12734    window->DrawList->ChannelsSplit(columns->Count);
    12735    PushColumnClipRect();
    12736    PushItemWidth(GetColumnWidth() * 0.65f);
    12737 }
    12738 
    12739 void ImGui::EndColumns()
    12740 {
    12741    ImGuiContext& g = *GImGui;
    12742    ImGuiWindow* window = GetCurrentWindow();
    12743    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
    12744    IM_ASSERT(columns != NULL);
    12745 
    12746    PopItemWidth();
    12747    PopClipRect();
    12748    window->DrawList->ChannelsMerge();
    12749 
    12750    columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
    12751    window->DC.CursorPos.y = columns->LineMaxY;
    12752    if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize))
    12753       window->DC.CursorMaxPos.x = columns->StartMaxPosX;  // Restore cursor max pos, as columns don't grow parent
    12754 
    12755                                                           // Draw columns borders and handle resize
    12756    bool is_being_resized = false;
    12757    if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
    12758    {
    12759       const float y1 = columns->StartPosY;
    12760       const float y2 = window->DC.CursorPos.y;
    12761       int dragging_column = -1;
    12762       for (int n = 1; n < columns->Count; n++)
    12763       {
    12764          float x = window->Pos.x + GetColumnOffset(n);
    12765          const ImGuiID column_id = columns->ID + ImGuiID(n);
    12766          const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction
    12767          const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2));
    12768          KeepAliveID(column_id);
    12769          if (IsClippedEx(column_rect, column_id, false))
    12770             continue;
    12771 
    12772          bool hovered = false, held = false;
    12773          if (!(columns->Flags & ImGuiColumnsFlags_NoResize))
    12774          {
    12775             ButtonBehavior(column_rect, column_id, &hovered, &held);
    12776             if (hovered || held)
    12777                g.MouseCursor = ImGuiMouseCursor_ResizeEW;
    12778             if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize))
    12779                dragging_column = n;
    12780          }
    12781 
    12782          // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.)
    12783          const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
    12784          const float xi = (float)(int)x;
    12785          window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col);
    12786       }
    12787 
    12788       // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
    12789       if (dragging_column != -1)
    12790       {
    12791          if (!columns->IsBeingResized)
    12792             for (int n = 0; n < columns->Count + 1; n++)
    12793                columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
    12794          columns->IsBeingResized = is_being_resized = true;
    12795          float x = GetDraggedColumnOffset(columns, dragging_column);
    12796          SetColumnOffset(dragging_column, x);
    12797       }
    12798    }
    12799    columns->IsBeingResized = is_being_resized;
    12800 
    12801    window->DC.ColumnsSet = NULL;
    12802    window->DC.ColumnsOffsetX = 0.0f;
    12803    window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
    12804 }
    12805 
    12806 // [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
    12807 void ImGui::Columns(int columns_count, const char* id, bool border)
    12808 {
    12809    ImGuiWindow* window = GetCurrentWindow();
    12810    IM_ASSERT(columns_count >= 1);
    12811 
    12812    ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
    12813    //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
    12814    if (window->DC.ColumnsSet != NULL && window->DC.ColumnsSet->Count == columns_count && window->DC.ColumnsSet->Flags == flags)
    12815       return;
    12816 
    12817    if (window->DC.ColumnsSet != NULL)
    12818       EndColumns();
    12819 
    12820    if (columns_count != 1)
    12821       BeginColumns(id, columns_count, flags);
    12822 }
    12823 
    12824 void ImGui::Indent(float indent_w)
    12825 {
    12826    ImGuiContext& g = *GImGui;
    12827    ImGuiWindow* window = GetCurrentWindow();
    12828    window->DC.IndentX += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
    12829    window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
    12830 }
    12831 
    12832 void ImGui::Unindent(float indent_w)
    12833 {
    12834    ImGuiContext& g = *GImGui;
    12835    ImGuiWindow* window = GetCurrentWindow();
    12836    window->DC.IndentX -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
    12837    window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
    12838 }
    12839 
    12840 void ImGui::TreePush(const char* str_id)
    12841 {
    12842    ImGuiWindow* window = GetCurrentWindow();
    12843    Indent();
    12844    window->DC.TreeDepth++;
    12845    PushID(str_id ? str_id : "#TreePush");
    12846 }
    12847 
    12848 void ImGui::TreePush(const void* ptr_id)
    12849 {
    12850    ImGuiWindow* window = GetCurrentWindow();
    12851    Indent();
    12852    window->DC.TreeDepth++;
    12853    PushID(ptr_id ? ptr_id : (const void*)"#TreePush");
    12854 }
    12855 
    12856 void ImGui::TreePushRawID(ImGuiID id)
    12857 {
    12858    ImGuiWindow* window = GetCurrentWindow();
    12859    Indent();
    12860    window->DC.TreeDepth++;
    12861    window->IDStack.push_back(id);
    12862 }
    12863 
    12864 void ImGui::TreePop()
    12865 {
    12866    ImGuiContext& g = *GImGui;
    12867    ImGuiWindow* window = g.CurrentWindow;
    12868    Unindent();
    12869 
    12870    window->DC.TreeDepth--;
    12871    if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
    12872       if (g.NavIdIsAlive && (window->DC.TreeDepthMayJumpToParentOnPop & (1 << window->DC.TreeDepth)))
    12873       {
    12874          SetNavID(window->IDStack.back(), g.NavLayer);
    12875          NavMoveRequestCancel();
    12876       }
    12877    window->DC.TreeDepthMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1;
    12878 
    12879    PopID();
    12880 }
    12881 
    12882 void ImGui::Value(const char* prefix, bool b)
    12883 {
    12884    Text("%s: %s", prefix, (b ? "true" : "false"));
    12885 }
    12886 
    12887 void ImGui::Value(const char* prefix, int v)
    12888 {
    12889    Text("%s: %d", prefix, v);
    12890 }
    12891 
    12892 void ImGui::Value(const char* prefix, unsigned int v)
    12893 {
    12894    Text("%s: %d", prefix, v);
    12895 }
    12896 
    12897 void ImGui::Value(const char* prefix, float v, const char* float_format)
    12898 {
    12899    if (float_format)
    12900    {
    12901       char fmt[64];
    12902       ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format);
    12903       Text(fmt, prefix, v);
    12904    }
    12905    else
    12906    {
    12907       Text("%s: %.3f", prefix, v);
    12908    }
    12909 }
     9301        const char* label = window->Name;
     9302        if (label == FindRenderedTextEnd(label))
     9303            label = GetFallbackWindowNameForWindowingList(window);
     9304        Selectable(label, g.NavWindowingTarget == window);
     9305    }
     9306    End();
     9307    PopStyleVar();
     9308}
     9309
    129109310
    129119311//-----------------------------------------------------------------------------
    12912 // DRAG AND DROP
     9312// [SECTION] DRAG AND DROP
    129139313//-----------------------------------------------------------------------------
    129149314
    129159315void ImGui::ClearDragDrop()
    129169316{
    12917    ImGuiContext& g = *GImGui;
    12918    g.DragDropActive = false;
    12919    g.DragDropPayload.Clear();
    12920    g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
    12921    g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
    12922    g.DragDropAcceptFrameCount = -1;
    12923 }
    12924 
    12925 // Call when current ID is active.
     9317    ImGuiContext& g = *GImGui;
     9318    g.DragDropActive = false;
     9319    g.DragDropPayload.Clear();
     9320    g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
     9321    g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
     9322    g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
     9323    g.DragDropAcceptFrameCount = -1;
     9324
     9325    g.DragDropPayloadBufHeap.clear();
     9326    memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
     9327}
     9328
     9329// Call when current ID is active.
    129269330// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
    129279331bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
    129289332{
    12929    ImGuiContext& g = *GImGui;
    12930    ImGuiWindow* window = g.CurrentWindow;
    12931 
    12932    bool source_drag_active = false;
    12933    ImGuiID source_id = 0;
    12934    ImGuiID source_parent_id = 0;
    12935    int mouse_button = 0;
    12936    if (!(flags & ImGuiDragDropFlags_SourceExtern))
    12937    {
    12938       source_id = window->DC.LastItemId;
    12939       if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case
    12940          return false;
    12941       if (g.IO.MouseDown[mouse_button] == false)
    12942          return false;
    12943 
    12944       if (source_id == 0)
    12945       {
    12946          // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
    12947          // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
    12948          if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
    12949          {
    12950             IM_ASSERT(0);
     9333    ImGuiContext& g = *GImGui;
     9334    ImGuiWindow* window = g.CurrentWindow;
     9335
     9336    bool source_drag_active = false;
     9337    ImGuiID source_id = 0;
     9338    ImGuiID source_parent_id = 0;
     9339    ImGuiMouseButton mouse_button = ImGuiMouseButton_Left;
     9340    if (!(flags & ImGuiDragDropFlags_SourceExtern))
     9341    {
     9342        source_id = window->DC.LastItemId;
     9343        if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case
    129519344            return false;
    12952          }
    12953 
    12954          // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
    12955          // We build a throwaway ID based on current ID stack + relative AABB of items in window.
    12956          // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
    12957          // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
    12958          bool is_hovered = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) != 0;
    12959          if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window))
     9345        if (g.IO.MouseDown[mouse_button] == false)
    129609346            return false;
    12961          source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
    12962          if (is_hovered)
    12963             SetHoveredID(source_id);
    12964          if (is_hovered && g.IO.MouseClicked[mouse_button])
    12965          {
    12966             SetActiveID(source_id, window);
    12967             FocusWindow(window);
    12968          }
    12969          if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
    12970             g.ActiveIdAllowOverlap = is_hovered;
    12971       }
    12972       if (g.ActiveId != source_id)
    12973          return false;
    12974       source_parent_id = window->IDStack.back();
    12975       source_drag_active = IsMouseDragging(mouse_button);
    12976    }
    12977    else
    12978    {
    12979       window = NULL;
    12980       source_id = ImHash("#SourceExtern", 0);
    12981       source_drag_active = true;
    12982    }
    12983 
    12984    if (source_drag_active)
    12985    {
    12986       if (!g.DragDropActive)
    12987       {
    12988          IM_ASSERT(source_id != 0);
    12989          ClearDragDrop();
    12990          ImGuiPayload& payload = g.DragDropPayload;
    12991          payload.SourceId = source_id;
    12992          payload.SourceParentId = source_parent_id;
    12993          g.DragDropActive = true;
    12994          g.DragDropSourceFlags = flags;
    12995          g.DragDropMouseButton = mouse_button;
    12996       }
    12997 
    12998       if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
    12999       {
    13000          // FIXME-DRAG
    13001          //SetNextWindowPos(g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding);
    13002          //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This is better but e.g ColorButton with checkboard has issue with transparent colors :(
    13003          SetNextWindowPos(g.IO.MousePos);
    13004          PushStyleColor(ImGuiCol_PopupBg, GetStyleColorVec4(ImGuiCol_PopupBg) * ImVec4(1.0f, 1.0f, 1.0f, 0.6f));
    13005          BeginTooltip();
    13006       }
    13007 
    13008       if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
    13009          window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
    13010 
    13011       return true;
    13012    }
    13013    return false;
     9347
     9348        if (source_id == 0)
     9349        {
     9350            // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
     9351            // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
     9352            if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
     9353            {
     9354                IM_ASSERT(0);
     9355                return false;
     9356            }
     9357
     9358            // Early out
     9359            if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
     9360                return false;
     9361
     9362            // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
     9363            // We build a throwaway ID based on current ID stack + relative AABB of items in window.
     9364            // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
     9365            // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
     9366            source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
     9367            bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id);
     9368            if (is_hovered && g.IO.MouseClicked[mouse_button])
     9369            {
     9370                SetActiveID(source_id, window);
     9371                FocusWindow(window);
     9372            }
     9373            if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
     9374                g.ActiveIdAllowOverlap = is_hovered;
     9375        }
     9376        else
     9377        {
     9378            g.ActiveIdAllowOverlap = false;
     9379        }
     9380        if (g.ActiveId != source_id)
     9381            return false;
     9382        source_parent_id = window->IDStack.back();
     9383        source_drag_active = IsMouseDragging(mouse_button);
     9384
     9385        // Disable navigation and key inputs while dragging
     9386        g.ActiveIdUsingNavDirMask = ~(ImU32)0;
     9387        g.ActiveIdUsingNavInputMask = ~(ImU32)0;
     9388        g.ActiveIdUsingKeyInputMask = ~(ImU64)0;
     9389    }
     9390    else
     9391    {
     9392        window = NULL;
     9393        source_id = ImHashStr("#SourceExtern");
     9394        source_drag_active = true;
     9395    }
     9396
     9397    if (source_drag_active)
     9398    {
     9399        if (!g.DragDropActive)
     9400        {
     9401            IM_ASSERT(source_id != 0);
     9402            ClearDragDrop();
     9403            ImGuiPayload& payload = g.DragDropPayload;
     9404            payload.SourceId = source_id;
     9405            payload.SourceParentId = source_parent_id;
     9406            g.DragDropActive = true;
     9407            g.DragDropSourceFlags = flags;
     9408            g.DragDropMouseButton = mouse_button;
     9409        }
     9410        g.DragDropSourceFrameCount = g.FrameCount;
     9411        g.DragDropWithinSource = true;
     9412
     9413        if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
     9414        {
     9415            // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
     9416            // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
     9417            BeginTooltip();
     9418            if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
     9419            {
     9420                ImGuiWindow* tooltip_window = g.CurrentWindow;
     9421                tooltip_window->SkipItems = true;
     9422                tooltip_window->HiddenFramesCanSkipItems = 1;
     9423            }
     9424        }
     9425
     9426        if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
     9427            window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
     9428
     9429        return true;
     9430    }
     9431    return false;
    130149432}
    130159433
    130169434void ImGui::EndDragDropSource()
    130179435{
    13018    ImGuiContext& g = *GImGui;
    13019    IM_ASSERT(g.DragDropActive);
    13020 
    13021    if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
    13022    {
    13023       EndTooltip();
    13024       PopStyleColor();
    13025       //PopStyleVar();
    13026    }
    13027 
    13028    // Discard the drag if have not called SetDragDropPayload()
    13029    if (g.DragDropPayload.DataFrameCount == -1)
    13030       ClearDragDrop();
     9436    ImGuiContext& g = *GImGui;
     9437    IM_ASSERT(g.DragDropActive);
     9438    IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?");
     9439
     9440    if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
     9441        EndTooltip();
     9442
     9443    // Discard the drag if have not called SetDragDropPayload()
     9444    if (g.DragDropPayload.DataFrameCount == -1)
     9445        ClearDragDrop();
     9446    g.DragDropWithinSource = false;
    130319447}
    130329448
     
    130349450bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
    130359451{
    13036    ImGuiContext& g = *GImGui;
    13037    ImGuiPayload& payload = g.DragDropPayload;
    13038    if (cond == 0)
    13039       cond = ImGuiCond_Always;
    13040 
    13041    IM_ASSERT(type != NULL);
    13042    IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 12 characters long");
    13043    IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
    13044    IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
    13045    IM_ASSERT(payload.SourceId != 0);                               // Not called between BeginDragDropSource() and EndDragDropSource()
    13046 
    13047    if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
    13048    {
    13049       // Copy payload
    13050       ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
    13051       g.DragDropPayloadBufHeap.resize(0);
    13052       if (data_size > sizeof(g.DragDropPayloadBufLocal))
    13053       {
    13054          // Store in heap
    13055          g.DragDropPayloadBufHeap.resize((int)data_size);
    13056          payload.Data = g.DragDropPayloadBufHeap.Data;
    13057          memcpy(payload.Data, data, data_size);
    13058       }
    13059       else if (data_size > 0)
    13060       {
    13061          // Store locally
    13062          memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
    13063          payload.Data = g.DragDropPayloadBufLocal;
    13064          memcpy(payload.Data, data, data_size);
    13065       }
    13066       else
    13067       {
    13068          payload.Data = NULL;
    13069       }
    13070       payload.DataSize = (int)data_size;
    13071    }
    13072    payload.DataFrameCount = g.FrameCount;
    13073 
    13074    return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
     9452    ImGuiContext& g = *GImGui;
     9453    ImGuiPayload& payload = g.DragDropPayload;
     9454    if (cond == 0)
     9455        cond = ImGuiCond_Always;
     9456
     9457    IM_ASSERT(type != NULL);
     9458    IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
     9459    IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
     9460    IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
     9461    IM_ASSERT(payload.SourceId != 0);                               // Not called between BeginDragDropSource() and EndDragDropSource()
     9462
     9463    if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
     9464    {
     9465        // Copy payload
     9466        ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
     9467        g.DragDropPayloadBufHeap.resize(0);
     9468        if (data_size > sizeof(g.DragDropPayloadBufLocal))
     9469        {
     9470            // Store in heap
     9471            g.DragDropPayloadBufHeap.resize((int)data_size);
     9472            payload.Data = g.DragDropPayloadBufHeap.Data;
     9473            memcpy(payload.Data, data, data_size);
     9474        }
     9475        else if (data_size > 0)
     9476        {
     9477            // Store locally
     9478            memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
     9479            payload.Data = g.DragDropPayloadBufLocal;
     9480            memcpy(payload.Data, data, data_size);
     9481        }
     9482        else
     9483        {
     9484            payload.Data = NULL;
     9485        }
     9486        payload.DataSize = (int)data_size;
     9487    }
     9488    payload.DataFrameCount = g.FrameCount;
     9489
     9490    return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
    130759491}
    130769492
    130779493bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
    130789494{
    13079    ImGuiContext& g = *GImGui;
    13080    if (!g.DragDropActive)
    13081       return false;
    13082 
    13083    ImGuiWindow* window = g.CurrentWindow;
    13084    if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
    13085       return false;
    13086    IM_ASSERT(id != 0);
    13087    if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
    13088       return false;
    13089 
    13090    g.DragDropTargetRect = bb;
    13091    g.DragDropTargetId = id;
    13092    return true;
     9495    ImGuiContext& g = *GImGui;
     9496    if (!g.DragDropActive)
     9497        return false;
     9498
     9499    ImGuiWindow* window = g.CurrentWindow;
     9500    ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
     9501    if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
     9502        return false;
     9503    IM_ASSERT(id != 0);
     9504    if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
     9505        return false;
     9506    if (window->SkipItems)
     9507        return false;
     9508
     9509    IM_ASSERT(g.DragDropWithinTarget == false);
     9510    g.DragDropTargetRect = bb;
     9511    g.DragDropTargetId = id;
     9512    g.DragDropWithinTarget = true;
     9513    return true;
    130939514}
    130949515
     
    130999520bool ImGui::BeginDragDropTarget()
    131009521{
    13101    ImGuiContext& g = *GImGui;
    13102    if (!g.DragDropActive)
    13103       return false;
    13104 
    13105    ImGuiWindow* window = g.CurrentWindow;
    13106    if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
    13107       return false;
    13108    if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
    13109       return false;
    13110 
    13111    const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
    13112    ImGuiID id = window->DC.LastItemId;
    13113    if (id == 0)
    13114       id = window->GetIDFromRectangle(display_rect);
    13115    if (g.DragDropPayload.SourceId == id)
    13116       return false;
    13117 
    13118    g.DragDropTargetRect = display_rect;
    13119    g.DragDropTargetId = id;
    13120    return true;
     9522    ImGuiContext& g = *GImGui;
     9523    if (!g.DragDropActive)
     9524        return false;
     9525
     9526    ImGuiWindow* window = g.CurrentWindow;
     9527    if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
     9528        return false;
     9529    ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
     9530    if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
     9531        return false;
     9532
     9533    const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
     9534    ImGuiID id = window->DC.LastItemId;
     9535    if (id == 0)
     9536        id = window->GetIDFromRectangle(display_rect);
     9537    if (g.DragDropPayload.SourceId == id)
     9538        return false;
     9539
     9540    IM_ASSERT(g.DragDropWithinTarget == false);
     9541    g.DragDropTargetRect = display_rect;
     9542    g.DragDropTargetId = id;
     9543    g.DragDropWithinTarget = true;
     9544    return true;
    131219545}
    131229546
    131239547bool ImGui::IsDragDropPayloadBeingAccepted()
    131249548{
    13125    ImGuiContext& g = *GImGui;
    13126    return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
     9549    ImGuiContext& g = *GImGui;
     9550    return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
    131279551}
    131289552
    131299553const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags)
    131309554{
    13131    ImGuiContext& g = *GImGui;
    13132    ImGuiWindow* window = g.CurrentWindow;
    13133    ImGuiPayload& payload = g.DragDropPayload;
    13134    IM_ASSERT(g.DragDropActive);                        // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
    13135    IM_ASSERT(payload.DataFrameCount != -1);            // Forgot to call EndDragDropTarget() ?
    13136    if (type != NULL && !payload.IsDataType(type))
    13137       return NULL;
    13138 
    13139    // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
    13140    // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
    13141    const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
    13142    ImRect r = g.DragDropTargetRect;
    13143    float r_surface = r.GetWidth() * r.GetHeight();
    13144    if (r_surface < g.DragDropAcceptIdCurrRectSurface)
    13145    {
    13146       g.DragDropAcceptIdCurr = g.DragDropTargetId;
    13147       g.DragDropAcceptIdCurrRectSurface = r_surface;
    13148    }
    13149 
    13150    // Render default drop visuals
    13151    payload.Preview = was_accepted_previously;
    13152    flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
    13153    if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
    13154    {
    13155       // FIXME-DRAG: Settle on a proper default visuals for drop target.
    13156       r.Expand(3.5f);
    13157       bool push_clip_rect = !window->ClipRect.Contains(r);
    13158       if (push_clip_rect) window->DrawList->PushClipRectFullScreen();
    13159       window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f);
    13160       if (push_clip_rect) window->DrawList->PopClipRect();
    13161    }
    13162 
    13163    g.DragDropAcceptFrameCount = g.FrameCount;
    13164    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()
    13165    if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
    13166       return NULL;
    13167 
    13168    return &payload;
     9555    ImGuiContext& g = *GImGui;
     9556    ImGuiWindow* window = g.CurrentWindow;
     9557    ImGuiPayload& payload = g.DragDropPayload;
     9558    IM_ASSERT(g.DragDropActive);                        // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
     9559    IM_ASSERT(payload.DataFrameCount != -1);            // Forgot to call EndDragDropTarget() ?
     9560    if (type != NULL && !payload.IsDataType(type))
     9561        return NULL;
     9562
     9563    // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
     9564    // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
     9565    const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
     9566    ImRect r = g.DragDropTargetRect;
     9567    float r_surface = r.GetWidth() * r.GetHeight();
     9568    if (r_surface < g.DragDropAcceptIdCurrRectSurface)
     9569    {
     9570        g.DragDropAcceptFlags = flags;
     9571        g.DragDropAcceptIdCurr = g.DragDropTargetId;
     9572        g.DragDropAcceptIdCurrRectSurface = r_surface;
     9573    }
     9574
     9575    // Render default drop visuals
     9576    payload.Preview = was_accepted_previously;
     9577    flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
     9578    if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
     9579    {
     9580        // FIXME-DRAG: Settle on a proper default visuals for drop target.
     9581        r.Expand(3.5f);
     9582        bool push_clip_rect = !window->ClipRect.Contains(r);
     9583        if (push_clip_rect) window->DrawList->PushClipRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1));
     9584        window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f);
     9585        if (push_clip_rect) window->DrawList->PopClipRect();
     9586    }
     9587
     9588    g.DragDropAcceptFrameCount = g.FrameCount;
     9589    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()
     9590    if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
     9591        return NULL;
     9592
     9593    return &payload;
     9594}
     9595
     9596const ImGuiPayload* ImGui::GetDragDropPayload()
     9597{
     9598    ImGuiContext& g = *GImGui;
     9599    return g.DragDropActive ? &g.DragDropPayload : NULL;
    131699600}
    131709601
     
    131729603void ImGui::EndDragDropTarget()
    131739604{
    13174    ImGuiContext& g = *GImGui; (void)g;
    13175    IM_ASSERT(g.DragDropActive);
     9605    ImGuiContext& g = *GImGui;
     9606    IM_ASSERT(g.DragDropActive);
     9607    IM_ASSERT(g.DragDropWithinTarget);
     9608    g.DragDropWithinTarget = false;
    131769609}
    131779610
    131789611//-----------------------------------------------------------------------------
    13179 // PLATFORM DEPENDENT HELPERS
     9612// [SECTION] LOGGING/CAPTURING
    131809613//-----------------------------------------------------------------------------
    13181 
    13182 #if defined(_WIN32) && !defined(_WINDOWS_) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS))
    13183 #undef WIN32_LEAN_AND_MEAN
    13184 #define WIN32_LEAN_AND_MEAN
    13185 #ifndef __MINGW32__
    13186 #include <Windows.h>
     9614// All text output from the interface can be captured into tty/file/clipboard.
     9615// By default, tree nodes are automatically opened during logging.
     9616//-----------------------------------------------------------------------------
     9617
     9618// Pass text data straight to log (without being displayed)
     9619void ImGui::LogText(const char* fmt, ...)
     9620{
     9621    ImGuiContext& g = *GImGui;
     9622    if (!g.LogEnabled)
     9623        return;
     9624
     9625    va_list args;
     9626    va_start(args, fmt);
     9627    if (g.LogFile)
     9628    {
     9629        g.LogBuffer.Buf.resize(0);
     9630        g.LogBuffer.appendfv(fmt, args);
     9631        ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);
     9632    }
     9633    else
     9634    {
     9635        g.LogBuffer.appendfv(fmt, args);
     9636    }
     9637    va_end(args);
     9638}
     9639
     9640// Internal version that takes a position to decide on newline placement and pad items according to their depth.
     9641// We split text into individual lines to add current tree level padding
     9642void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)
     9643{
     9644    ImGuiContext& g = *GImGui;
     9645    ImGuiWindow* window = g.CurrentWindow;
     9646
     9647    if (!text_end)
     9648        text_end = FindRenderedTextEnd(text, text_end);
     9649
     9650    const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1);
     9651    if (ref_pos)
     9652        g.LogLinePosY = ref_pos->y;
     9653    if (log_new_line)
     9654        g.LogLineFirstItem = true;
     9655
     9656    const char* text_remaining = text;
     9657    if (g.LogDepthRef > window->DC.TreeDepth)  // Re-adjust padding if we have popped out of our starting depth
     9658        g.LogDepthRef = window->DC.TreeDepth;
     9659    const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef);
     9660    for (;;)
     9661    {
     9662        // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
     9663        // We don't add a trailing \n to allow a subsequent item on the same line to be captured.
     9664        const char* line_start = text_remaining;
     9665        const char* line_end = ImStreolRange(line_start, text_end);
     9666        const bool is_first_line = (line_start == text);
     9667        const bool is_last_line = (line_end == text_end);
     9668        if (!is_last_line || (line_start != line_end))
     9669        {
     9670            const int char_count = (int)(line_end - line_start);
     9671            if (log_new_line || !is_first_line)
     9672                LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start);
     9673            else if (g.LogLineFirstItem)
     9674                LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start);
     9675            else
     9676                LogText(" %.*s", char_count, line_start);
     9677            g.LogLineFirstItem = false;
     9678        }
     9679        else if (log_new_line)
     9680        {
     9681            // An empty "" string at a different Y position should output a carriage return.
     9682            LogText(IM_NEWLINE);
     9683            break;
     9684        }
     9685
     9686        if (is_last_line)
     9687            break;
     9688        text_remaining = line_end + 1;
     9689    }
     9690}
     9691
     9692// Start logging/capturing text output
     9693void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)
     9694{
     9695    ImGuiContext& g = *GImGui;
     9696    ImGuiWindow* window = g.CurrentWindow;
     9697    IM_ASSERT(g.LogEnabled == false);
     9698    IM_ASSERT(g.LogFile == NULL);
     9699    IM_ASSERT(g.LogBuffer.empty());
     9700    g.LogEnabled = true;
     9701    g.LogType = type;
     9702    g.LogDepthRef = window->DC.TreeDepth;
     9703    g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault);
     9704    g.LogLinePosY = FLT_MAX;
     9705    g.LogLineFirstItem = true;
     9706}
     9707
     9708void ImGui::LogToTTY(int auto_open_depth)
     9709{
     9710    ImGuiContext& g = *GImGui;
     9711    if (g.LogEnabled)
     9712        return;
     9713    IM_UNUSED(auto_open_depth);
     9714#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
     9715    LogBegin(ImGuiLogType_TTY, auto_open_depth);
     9716    g.LogFile = stdout;
     9717#endif
     9718}
     9719
     9720// Start logging/capturing text output to given file
     9721void ImGui::LogToFile(int auto_open_depth, const char* filename)
     9722{
     9723    ImGuiContext& g = *GImGui;
     9724    if (g.LogEnabled)
     9725        return;
     9726
     9727    // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still
     9728    // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE.
     9729    // By opening the file in binary mode "ab" we have consistent output everywhere.
     9730    if (!filename)
     9731        filename = g.IO.LogFilename;
     9732    if (!filename || !filename[0])
     9733        return;
     9734    ImFileHandle f = ImFileOpen(filename, "ab");
     9735    if (!f)
     9736    {
     9737        IM_ASSERT(0);
     9738        return;
     9739    }
     9740
     9741    LogBegin(ImGuiLogType_File, auto_open_depth);
     9742    g.LogFile = f;
     9743}
     9744
     9745// Start logging/capturing text output to clipboard
     9746void ImGui::LogToClipboard(int auto_open_depth)
     9747{
     9748    ImGuiContext& g = *GImGui;
     9749    if (g.LogEnabled)
     9750        return;
     9751    LogBegin(ImGuiLogType_Clipboard, auto_open_depth);
     9752}
     9753
     9754void ImGui::LogToBuffer(int auto_open_depth)
     9755{
     9756    ImGuiContext& g = *GImGui;
     9757    if (g.LogEnabled)
     9758        return;
     9759    LogBegin(ImGuiLogType_Buffer, auto_open_depth);
     9760}
     9761
     9762void ImGui::LogFinish()
     9763{
     9764    ImGuiContext& g = *GImGui;
     9765    if (!g.LogEnabled)
     9766        return;
     9767
     9768    LogText(IM_NEWLINE);
     9769    switch (g.LogType)
     9770    {
     9771    case ImGuiLogType_TTY:
     9772#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
     9773        fflush(g.LogFile);
     9774#endif
     9775        break;
     9776    case ImGuiLogType_File:
     9777        ImFileClose(g.LogFile);
     9778        break;
     9779    case ImGuiLogType_Buffer:
     9780        break;
     9781    case ImGuiLogType_Clipboard:
     9782        if (!g.LogBuffer.empty())
     9783            SetClipboardText(g.LogBuffer.begin());
     9784        break;
     9785    case ImGuiLogType_None:
     9786        IM_ASSERT(0);
     9787        break;
     9788    }
     9789
     9790    g.LogEnabled = false;
     9791    g.LogType = ImGuiLogType_None;
     9792    g.LogFile = NULL;
     9793    g.LogBuffer.clear();
     9794}
     9795
     9796// Helper to display logging buttons
     9797// FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!)
     9798void ImGui::LogButtons()
     9799{
     9800    ImGuiContext& g = *GImGui;
     9801
     9802    PushID("LogButtons");
     9803#ifndef IMGUI_DISABLE_TTY_FUNCTIONS
     9804    const bool log_to_tty = Button("Log To TTY"); SameLine();
    131879805#else
    13188 #include <windows.h>
     9806    const bool log_to_tty = false;
    131899807#endif
     9808    const bool log_to_file = Button("Log To File"); SameLine();
     9809    const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
     9810    PushAllowKeyboardFocus(false);
     9811    SetNextItemWidth(80.0f);
     9812    SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL);
     9813    PopAllowKeyboardFocus();
     9814    PopID();
     9815
     9816    // Start logging at the end of the function so that the buttons don't appear in the log
     9817    if (log_to_tty)
     9818        LogToTTY();
     9819    if (log_to_file)
     9820        LogToFile();
     9821    if (log_to_clipboard)
     9822        LogToClipboard();
     9823}
     9824
     9825
     9826//-----------------------------------------------------------------------------
     9827// [SECTION] SETTINGS
     9828//-----------------------------------------------------------------------------
     9829// - UpdateSettings() [Internal]
     9830// - MarkIniSettingsDirty() [Internal]
     9831// - CreateNewWindowSettings() [Internal]
     9832// - FindWindowSettings() [Internal]
     9833// - FindOrCreateWindowSettings() [Internal]
     9834// - FindSettingsHandler() [Internal]
     9835// - ClearIniSettings() [Internal]
     9836// - LoadIniSettingsFromDisk()
     9837// - LoadIniSettingsFromMemory()
     9838// - SaveIniSettingsToDisk()
     9839// - SaveIniSettingsToMemory()
     9840// - WindowSettingsHandler_***() [Internal]
     9841//-----------------------------------------------------------------------------
     9842
     9843// Called by NewFrame()
     9844void ImGui::UpdateSettings()
     9845{
     9846    // Load settings on first frame (if not explicitly loaded manually before)
     9847    ImGuiContext& g = *GImGui;
     9848    if (!g.SettingsLoaded)
     9849    {
     9850        IM_ASSERT(g.SettingsWindows.empty());
     9851        if (g.IO.IniFilename)
     9852            LoadIniSettingsFromDisk(g.IO.IniFilename);
     9853        g.SettingsLoaded = true;
     9854    }
     9855
     9856    // Save settings (with a delay after the last modification, so we don't spam disk too much)
     9857    if (g.SettingsDirtyTimer > 0.0f)
     9858    {
     9859        g.SettingsDirtyTimer -= g.IO.DeltaTime;
     9860        if (g.SettingsDirtyTimer <= 0.0f)
     9861        {
     9862            if (g.IO.IniFilename != NULL)
     9863                SaveIniSettingsToDisk(g.IO.IniFilename);
     9864            else
     9865                g.IO.WantSaveIniSettings = true;  // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
     9866            g.SettingsDirtyTimer = 0.0f;
     9867        }
     9868    }
     9869}
     9870
     9871void ImGui::MarkIniSettingsDirty()
     9872{
     9873    ImGuiContext& g = *GImGui;
     9874    if (g.SettingsDirtyTimer <= 0.0f)
     9875        g.SettingsDirtyTimer = g.IO.IniSavingRate;
     9876}
     9877
     9878void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
     9879{
     9880    ImGuiContext& g = *GImGui;
     9881    if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
     9882        if (g.SettingsDirtyTimer <= 0.0f)
     9883            g.SettingsDirtyTimer = g.IO.IniSavingRate;
     9884}
     9885
     9886ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
     9887{
     9888    ImGuiContext& g = *GImGui;
     9889
     9890#if !IMGUI_DEBUG_INI_SETTINGS
     9891    // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
     9892    // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
     9893    if (const char* p = strstr(name, "###"))
     9894        name = p;
    131909895#endif
    13191 
    13192 // Win32 API clipboard implementation
    13193 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
     9896    const size_t name_len = strlen(name);
     9897
     9898    // Allocate chunk
     9899    const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
     9900    ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
     9901    IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
     9902    settings->ID = ImHashStr(name, name_len);
     9903    memcpy(settings->GetName(), name, name_len + 1);   // Store with zero terminator
     9904
     9905    return settings;
     9906}
     9907
     9908ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
     9909{
     9910    ImGuiContext& g = *GImGui;
     9911    for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
     9912        if (settings->ID == id)
     9913            return settings;
     9914    return NULL;
     9915}
     9916
     9917ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
     9918{
     9919    if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name)))
     9920        return settings;
     9921    return CreateNewWindowSettings(name);
     9922}
     9923
     9924ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
     9925{
     9926    ImGuiContext& g = *GImGui;
     9927    const ImGuiID type_hash = ImHashStr(type_name);
     9928    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
     9929        if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
     9930            return &g.SettingsHandlers[handler_n];
     9931    return NULL;
     9932}
     9933
     9934void ImGui::ClearIniSettings()
     9935{
     9936    ImGuiContext& g = *GImGui;
     9937    g.SettingsIniData.clear();
     9938    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
     9939        if (g.SettingsHandlers[handler_n].ClearAllFn)
     9940            g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]);
     9941}
     9942
     9943void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
     9944{
     9945    size_t file_data_size = 0;
     9946    char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
     9947    if (!file_data)
     9948        return;
     9949    LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
     9950    IM_FREE(file_data);
     9951}
     9952
     9953// Zero-tolerance, no error reporting, cheap .ini parsing
     9954void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
     9955{
     9956    ImGuiContext& g = *GImGui;
     9957    IM_ASSERT(g.Initialized);
     9958    //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()");
     9959    //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
     9960
     9961    // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
     9962    // 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..
     9963    if (ini_size == 0)
     9964        ini_size = strlen(ini_data);
     9965    g.SettingsIniData.Buf.resize((int)ini_size + 1);
     9966    char* const buf = g.SettingsIniData.Buf.Data;
     9967    char* const buf_end = buf + ini_size;
     9968    memcpy(buf, ini_data, ini_size);
     9969    buf_end[0] = 0;
     9970
     9971    // Call pre-read handlers
     9972    // Some types will clear their data (e.g. dock information) some types will allow merge/override (window)
     9973    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
     9974        if (g.SettingsHandlers[handler_n].ReadInitFn)
     9975            g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]);
     9976
     9977    void* entry_data = NULL;
     9978    ImGuiSettingsHandler* entry_handler = NULL;
     9979
     9980    char* line_end = NULL;
     9981    for (char* line = buf; line < buf_end; line = line_end + 1)
     9982    {
     9983        // Skip new lines markers, then find end of the line
     9984        while (*line == '\n' || *line == '\r')
     9985            line++;
     9986        line_end = line;
     9987        while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
     9988            line_end++;
     9989        line_end[0] = 0;
     9990        if (line[0] == ';')
     9991            continue;
     9992        if (line[0] == '[' && line_end > line && line_end[-1] == ']')
     9993        {
     9994            // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
     9995            line_end[-1] = 0;
     9996            const char* name_end = line_end - 1;
     9997            const char* type_start = line + 1;
     9998            char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');
     9999            const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
     10000            if (!type_end || !name_start)
     10001                continue;
     10002            *type_end = 0; // Overwrite first ']'
     10003            name_start++;  // Skip second '['
     10004            entry_handler = FindSettingsHandler(type_start);
     10005            entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
     10006        }
     10007        else if (entry_handler != NULL && entry_data != NULL)
     10008        {
     10009            // Let type handler parse the line
     10010            entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
     10011        }
     10012    }
     10013    g.SettingsLoaded = true;
     10014
     10015    // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary)
     10016    memcpy(buf, ini_data, ini_size);
     10017
     10018    // Call post-read handlers
     10019    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
     10020        if (g.SettingsHandlers[handler_n].ApplyAllFn)
     10021            g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]);
     10022}
     10023
     10024void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
     10025{
     10026    ImGuiContext& g = *GImGui;
     10027    g.SettingsDirtyTimer = 0.0f;
     10028    if (!ini_filename)
     10029        return;
     10030
     10031    size_t ini_data_size = 0;
     10032    const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
     10033    ImFileHandle f = ImFileOpen(ini_filename, "wt");
     10034    if (!f)
     10035        return;
     10036    ImFileWrite(ini_data, sizeof(char), ini_data_size, f);
     10037    ImFileClose(f);
     10038}
     10039
     10040// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
     10041const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
     10042{
     10043    ImGuiContext& g = *GImGui;
     10044    g.SettingsDirtyTimer = 0.0f;
     10045    g.SettingsIniData.Buf.resize(0);
     10046    g.SettingsIniData.Buf.push_back(0);
     10047    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
     10048    {
     10049        ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
     10050        handler->WriteAllFn(&g, handler, &g.SettingsIniData);
     10051    }
     10052    if (out_size)
     10053        *out_size = (size_t)g.SettingsIniData.size();
     10054    return g.SettingsIniData.c_str();
     10055}
     10056
     10057static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
     10058{
     10059    ImGuiContext& g = *ctx;
     10060    for (int i = 0; i != g.Windows.Size; i++)
     10061        g.Windows[i]->SettingsOffset = -1;
     10062    g.SettingsWindows.clear();
     10063}
     10064
     10065static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
     10066{
     10067    ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name);
     10068    ImGuiID id = settings->ID;
     10069    *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry
     10070    settings->ID = id;
     10071    settings->WantApply = true;
     10072    return (void*)settings;
     10073}
     10074
     10075static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
     10076{
     10077    ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
     10078    int x, y;
     10079    int i;
     10080    if (sscanf(line, "Pos=%i,%i", &x, &y) == 2)         { settings->Pos = ImVec2ih((short)x, (short)y); }
     10081    else if (sscanf(line, "Size=%i,%i", &x, &y) == 2)   { settings->Size = ImVec2ih((short)x, (short)y); }
     10082    else if (sscanf(line, "Collapsed=%d", &i) == 1)     { settings->Collapsed = (i != 0); }
     10083}
     10084
     10085// Apply to existing windows (if any)
     10086static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
     10087{
     10088    ImGuiContext& g = *ctx;
     10089    for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
     10090        if (settings->WantApply)
     10091        {
     10092            if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID))
     10093                ApplyWindowSettings(window, settings);
     10094            settings->WantApply = false;
     10095        }
     10096}
     10097
     10098static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
     10099{
     10100    // Gather data from windows that were active during this session
     10101    // (if a window wasn't opened in this session we preserve its settings)
     10102    ImGuiContext& g = *ctx;
     10103    for (int i = 0; i != g.Windows.Size; i++)
     10104    {
     10105        ImGuiWindow* window = g.Windows[i];
     10106        if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
     10107            continue;
     10108
     10109        ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID);
     10110        if (!settings)
     10111        {
     10112            settings = ImGui::CreateNewWindowSettings(window->Name);
     10113            window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
     10114        }
     10115        IM_ASSERT(settings->ID == window->ID);
     10116        settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y);
     10117        settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y);
     10118        settings->Collapsed = window->Collapsed;
     10119    }
     10120
     10121    // Write to text buffer
     10122    buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
     10123    for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
     10124    {
     10125        const char* settings_name = settings->GetName();
     10126        buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
     10127        buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
     10128        buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
     10129        buf->appendf("Collapsed=%d\n", settings->Collapsed);
     10130        buf->append("\n");
     10131    }
     10132}
     10133
     10134
     10135//-----------------------------------------------------------------------------
     10136// [SECTION] VIEWPORTS, PLATFORM WINDOWS
     10137//-----------------------------------------------------------------------------
     10138
     10139// (this section is filled in the 'docking' branch)
     10140
     10141
     10142//-----------------------------------------------------------------------------
     10143// [SECTION] DOCKING
     10144//-----------------------------------------------------------------------------
     10145
     10146// (this section is filled in the 'docking' branch)
     10147
     10148
     10149//-----------------------------------------------------------------------------
     10150// [SECTION] PLATFORM DEPENDENT HELPERS
     10151//-----------------------------------------------------------------------------
     10152
     10153#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
    1319410154
    1319510155#ifdef _MSC_VER
    1319610156#pragma comment(lib, "user32")
     10157#pragma comment(lib, "kernel32")
    1319710158#endif
    1319810159
     10160// Win32 clipboard implementation
     10161// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown()
    1319910162static const char* GetClipboardTextFn_DefaultImpl(void*)
    1320010163{
    13201    static ImVector<char> buf_local;
    13202    buf_local.clear();
    13203    if (!OpenClipboard(NULL))
    13204       return NULL;
    13205    HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
    13206    if (wbuf_handle == NULL)
    13207    {
    13208       CloseClipboard();
    13209       return NULL;
    13210    }
    13211    if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
    13212    {
    13213       int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
    13214       buf_local.resize(buf_len);
    13215       ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);
    13216    }
    13217    GlobalUnlock(wbuf_handle);
    13218    CloseClipboard();
    13219    return buf_local.Data;
     10164    ImGuiContext& g = *GImGui;
     10165    g.ClipboardHandlerData.clear();
     10166    if (!::OpenClipboard(NULL))
     10167        return NULL;
     10168    HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
     10169    if (wbuf_handle == NULL)
     10170    {
     10171        ::CloseClipboard();
     10172        return NULL;
     10173    }
     10174    if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
     10175    {
     10176        int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
     10177        g.ClipboardHandlerData.resize(buf_len);
     10178        ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
     10179    }
     10180    ::GlobalUnlock(wbuf_handle);
     10181    ::CloseClipboard();
     10182    return g.ClipboardHandlerData.Data;
    1322010183}
    1322110184
    1322210185static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
    1322310186{
    13224    if (!OpenClipboard(NULL))
    13225       return;
    13226    const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
    13227    HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
    13228    if (wbuf_handle == NULL)
    13229    {
    13230       CloseClipboard();
    13231       return;
    13232    }
    13233    ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle);
    13234    ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL);
    13235    GlobalUnlock(wbuf_handle);
    13236    EmptyClipboard();
    13237    SetClipboardData(CF_UNICODETEXT, wbuf_handle);
    13238    CloseClipboard();
     10187    if (!::OpenClipboard(NULL))
     10188        return;
     10189    const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
     10190    HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
     10191    if (wbuf_handle == NULL)
     10192    {
     10193        ::CloseClipboard();
     10194        return;
     10195    }
     10196    WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
     10197    ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
     10198    ::GlobalUnlock(wbuf_handle);
     10199    ::EmptyClipboard();
     10200    if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
     10201        ::GlobalFree(wbuf_handle);
     10202    ::CloseClipboard();
     10203}
     10204
     10205#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
     10206
     10207#include <Carbon/Carbon.h>  // Use old API to avoid need for separate .mm file
     10208static PasteboardRef main_clipboard = 0;
     10209
     10210// OSX clipboard implementation
     10211// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!
     10212static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
     10213{
     10214    if (!main_clipboard)
     10215        PasteboardCreate(kPasteboardClipboard, &main_clipboard);
     10216    PasteboardClear(main_clipboard);
     10217    CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));
     10218    if (cf_data)
     10219    {
     10220        PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
     10221        CFRelease(cf_data);
     10222    }
     10223}
     10224
     10225static const char* GetClipboardTextFn_DefaultImpl(void*)
     10226{
     10227    if (!main_clipboard)
     10228        PasteboardCreate(kPasteboardClipboard, &main_clipboard);
     10229    PasteboardSynchronize(main_clipboard);
     10230
     10231    ItemCount item_count = 0;
     10232    PasteboardGetItemCount(main_clipboard, &item_count);
     10233    for (ItemCount i = 0; i < item_count; i++)
     10234    {
     10235        PasteboardItemID item_id = 0;
     10236        PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
     10237        CFArrayRef flavor_type_array = 0;
     10238        PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
     10239        for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
     10240        {
     10241            CFDataRef cf_data;
     10242            if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
     10243            {
     10244                ImGuiContext& g = *GImGui;
     10245                g.ClipboardHandlerData.clear();
     10246                int length = (int)CFDataGetLength(cf_data);
     10247                g.ClipboardHandlerData.resize(length + 1);
     10248                CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data);
     10249                g.ClipboardHandlerData[length] = 0;
     10250                CFRelease(cf_data);
     10251                return g.ClipboardHandlerData.Data;
     10252            }
     10253        }
     10254    }
     10255    return NULL;
    1323910256}
    1324010257
    1324110258#else
    1324210259
    13243 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
     10260// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
    1324410261static const char* GetClipboardTextFn_DefaultImpl(void*)
    1324510262{
    13246    ImGuiContext& g = *GImGui;
    13247    return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin();
    13248 }
    13249 
    13250 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
     10263    ImGuiContext& g = *GImGui;
     10264    return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();
     10265}
     10266
    1325110267static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
    1325210268{
    13253    ImGuiContext& g = *GImGui;
    13254    g.PrivateClipboard.clear();
    13255    const char* text_end = text + strlen(text);
    13256    g.PrivateClipboard.resize((int)(text_end - text) + 1);
    13257    memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text));
    13258    g.PrivateClipboard[(int)(text_end - text)] = 0;
     10269    ImGuiContext& g = *GImGui;
     10270    g.ClipboardHandlerData.clear();
     10271    const char* text_end = text + strlen(text);
     10272    g.ClipboardHandlerData.resize((int)(text_end - text) + 1);
     10273    memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text));
     10274    g.ClipboardHandlerData[(int)(text_end - text)] = 0;
    1325910275}
    1326010276
     
    1326210278
    1326310279// Win32 API IME support (for Asian languages, etc.)
    13264 #if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
     10280#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
    1326510281
    1326610282#include <imm.h>
     
    1327110287static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
    1327210288{
    13273    // Notify OS Input Method Editor of text input position
    13274    if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle)
    13275       if (HIMC himc = ImmGetContext(hwnd))
    13276       {
    13277          COMPOSITIONFORM cf;
    13278          cf.ptCurrentPos.x = x;
    13279          cf.ptCurrentPos.y = y;
    13280          cf.dwStyle = CFS_FORCE_POSITION;
    13281          ImmSetCompositionWindow(himc, &cf);
    13282       }
     10289    // Notify OS Input Method Editor of text input position
     10290    ImGuiIO& io = ImGui::GetIO();
     10291    if (HWND hwnd = (HWND)io.ImeWindowHandle)
     10292        if (HIMC himc = ::ImmGetContext(hwnd))
     10293        {
     10294            COMPOSITIONFORM cf;
     10295            cf.ptCurrentPos.x = x;
     10296            cf.ptCurrentPos.y = y;
     10297            cf.dwStyle = CFS_FORCE_POSITION;
     10298            ::ImmSetCompositionWindow(himc, &cf);
     10299            ::ImmReleaseContext(hwnd, himc);
     10300        }
    1328310301}
    1328410302
     
    1329010308
    1329110309//-----------------------------------------------------------------------------
    13292 // HELP, METRICS
     10310// [SECTION] METRICS/DEBUG WINDOW
    1329310311//-----------------------------------------------------------------------------
    1329410312
     10313#ifndef IMGUI_DISABLE_METRICS_WINDOW
     10314// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
     10315static void MetricsHelpMarker(const char* desc)
     10316{
     10317    ImGui::TextDisabled("(?)");
     10318    if (ImGui::IsItemHovered())
     10319    {
     10320        ImGui::BeginTooltip();
     10321        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
     10322        ImGui::TextUnformatted(desc);
     10323        ImGui::PopTextWrapPos();
     10324        ImGui::EndTooltip();
     10325    }
     10326}
     10327
    1329510328void ImGui::ShowMetricsWindow(bool* p_open)
    1329610329{
    13297    if (ImGui::Begin("ImGui Metrics", p_open))
    13298    {
    13299       ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
    13300       ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
    13301       ImGui::Text("%d vertices, %d indices (%d triangles)", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices, ImGui::GetIO().MetricsRenderIndices / 3);
    13302       ImGui::Text("%d allocations", (int)GImAllocatorActiveAllocationsCount);
    13303       static bool show_clip_rects = true;
    13304       ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_clip_rects);
    13305       ImGui::Separator();
    13306 
    13307       struct Funcs
    13308       {
    13309          static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
    13310          {
     10330    if (!ImGui::Begin("Dear ImGui Metrics", p_open))
     10331    {
     10332        ImGui::End();
     10333        return;
     10334    }
     10335
     10336    // Debugging enums
     10337    enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type
     10338    const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" };
     10339    enum { TRT_OuterRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentRowsFrozen, TRT_ColumnsContentRowsUnfrozen, TRT_Count }; // Tables Rect Type
     10340    const char* trt_rects_names[TRT_Count] = { "OuterRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentRowsFrozen", "ColumnsContentRowsUnfrozen" };
     10341
     10342    // State
     10343    static bool show_windows_rects = false;
     10344    static int  show_windows_rect_type = WRT_WorkRect;
     10345    static bool show_windows_begin_order = false;
     10346    static bool show_tables_rects = false;
     10347    static int  show_tables_rect_type = TRT_WorkRect;
     10348    static bool show_drawcmd_mesh = true;
     10349    static bool show_drawcmd_aabb = true;
     10350
     10351    // Basic info
     10352    ImGuiContext& g = *GImGui;
     10353    ImGuiIO& io = ImGui::GetIO();
     10354    ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
     10355    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
     10356    ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
     10357    ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows);
     10358    ImGui::Text("%d active allocations", io.MetricsActiveAllocations);
     10359    ImGui::Separator();
     10360
     10361    // Helper functions to display common structures:
     10362    // - NodeDrawList()
     10363    // - NodeColumns()
     10364    // - NodeWindow()
     10365    // - NodeWindows()
     10366    // - NodeTabBar()
     10367    // - NodeStorage()
     10368    struct Funcs
     10369    {
     10370        static ImRect GetWindowRect(ImGuiWindow* window, int rect_type)
     10371        {
     10372            if (rect_type == WRT_OuterRect)                 { return window->Rect(); }
     10373            else if (rect_type == WRT_OuterRectClipped)     { return window->OuterRectClipped; }
     10374            else if (rect_type == WRT_InnerRect)            { return window->InnerRect; }
     10375            else if (rect_type == WRT_InnerClipRect)        { return window->InnerClipRect; }
     10376            else if (rect_type == WRT_WorkRect)             { return window->WorkRect; }
     10377            else if (rect_type == WRT_Content)              { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
     10378            else if (rect_type == WRT_ContentRegionRect)    { return window->ContentRegionRect; }
     10379            IM_ASSERT(0);
     10380            return ImRect();
     10381        }
     10382
     10383        static void NodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, int elem_offset, bool show_mesh, bool show_aabb)
     10384        {
     10385            IM_ASSERT(show_mesh || show_aabb);
     10386            ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
     10387            ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
     10388
     10389            // Draw wire-frame version of all triangles
     10390            ImRect clip_rect = draw_cmd->ClipRect;
     10391            ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
     10392            ImDrawListFlags backup_flags = fg_draw_list->Flags;
     10393            fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
     10394            for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + draw_cmd->ElemCount); base_idx += 3)
     10395            {
     10396                ImVec2 triangle[3];
     10397                for (int n = 0; n < 3; n++)
     10398                {
     10399                    ImVec2 p = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos;
     10400                    triangle[n] = p;
     10401                    vtxs_rect.Add(p);
     10402                }
     10403                if (show_mesh)
     10404                    fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); // In yellow: mesh triangles
     10405            }
     10406            // Draw bounding boxes
     10407            if (show_aabb)
     10408            {
     10409                fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU
     10410                fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles
     10411            }
     10412            fg_draw_list->Flags = backup_flags;
     10413        }
     10414
     10415        static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
     10416        {
    1331110417            bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size);
    1331210418            if (draw_list == ImGui::GetWindowDrawList())
    1331310419            {
    13314                ImGui::SameLine();
    13315                ImGui::TextColored(ImColor(255, 100, 100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
    13316                if (node_open) ImGui::TreePop();
    13317                return;
     10420                ImGui::SameLine();
     10421                ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
     10422                if (node_open) ImGui::TreePop();
     10423                return;
    1331810424            }
    1331910425
    13320             ImDrawList* overlay_draw_list = GetOverlayDrawList(); // Render additional visuals into the top-most draw list
     10426            ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
    1332110427            if (window && IsItemHovered())
    13322                overlay_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
     10428                fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
    1332310429            if (!node_open)
    13324                return;
    13325 
    13326             int elem_offset = 0;
     10430                return;
     10431
     10432            if (window && !window->WasActive)
     10433                ImGui::TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!");
     10434
     10435            unsigned int elem_offset = 0;
    1332710436            for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
    1332810437            {
    13329                if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0)
    13330                   continue;
    13331                if (pcmd->UserCallback)
    13332                {
    13333                   ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
    13334                   continue;
    13335                }
    13336                ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
    13337                bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
    13338                if (show_clip_rects && ImGui::IsItemHovered())
    13339                {
    13340                   ImRect clip_rect = pcmd->ClipRect;
    13341                   ImRect vtxs_rect;
    13342                   for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
    13343                      vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
    13344                   clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255, 255, 0, 255));
    13345                   vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255, 0, 255, 255));
    13346                }
    13347                if (!pcmd_node_open)
    13348                   continue;
    13349 
    13350                // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
    13351                ImGuiListClipper clipper(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
    13352                while (clipper.Step())
    13353                   for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++)
    13354                   {
    13355                      char buf[300];
    13356                      char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
    13357                      ImVec2 triangles_pos[3];
    13358                      for (int n = 0; n < 3; n++, vtx_i++)
    13359                      {
    13360                         ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i];
    13361                         triangles_pos[n] = v.pos;
    13362                         buf_p += ImFormatString(buf_p, (int)(buf_end - buf_p), "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : "   ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
    13363                      }
    13364                      ImGui::Selectable(buf, false);
    13365                      if (ImGui::IsItemHovered())
    13366                      {
    13367                         ImDrawListFlags backup_flags = overlay_draw_list->Flags;
    13368                         overlay_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles.
    13369                         overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255, 255, 0, 255), true, 1.0f);
    13370                         overlay_draw_list->Flags = backup_flags;
    13371                      }
    13372                   }
    13373                ImGui::TreePop();
     10438                if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0)
     10439                    continue;
     10440                if (pcmd->UserCallback)
     10441                {
     10442                    ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
     10443                    continue;
     10444                }
     10445
     10446                ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
     10447                char buf[300];
     10448                ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d triangles, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
     10449                    pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId,
     10450                    pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
     10451                bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
     10452                if (ImGui::IsItemHovered() && (show_drawcmd_mesh || show_drawcmd_aabb) && fg_draw_list)
     10453                    NodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, elem_offset, show_drawcmd_mesh, show_drawcmd_aabb);
     10454                if (!pcmd_node_open)
     10455                    continue;
     10456
     10457                // Calculate approximate coverage area (touched pixel count)
     10458                // This will be in pixels squared as long there's no post-scaling happening to the renderer output.
     10459                float total_area = 0.0f;
     10460                for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3)
     10461                {
     10462                    ImVec2 triangle[3];
     10463                    for (int n = 0; n < 3; n++)
     10464                        triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos;
     10465                    total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);
     10466                }
     10467
     10468                // Display vertex information summary. Hover to get all triangles drawn in wire-frame
     10469                ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);
     10470                ImGui::Selectable(buf);
     10471                if (ImGui::IsItemHovered() && fg_draw_list)
     10472                    NodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, elem_offset, true, false);
     10473
     10474                // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
     10475                ImGuiListClipper clipper;
     10476                clipper.Begin(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
     10477                while (clipper.Step())
     10478                    for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++)
     10479                    {
     10480                        char* buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
     10481                        ImVec2 triangle[3];
     10482                        for (int n = 0; n < 3; n++, idx_i++)
     10483                        {
     10484                            ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[idx_i] : idx_i];
     10485                            triangle[n] = v.pos;
     10486                            buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
     10487                                (n == 0) ? "Vert:" : "     ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
     10488                        }
     10489
     10490                        ImGui::Selectable(buf, false);
     10491                        if (fg_draw_list && ImGui::IsItemHovered())
     10492                        {
     10493                            ImDrawListFlags backup_flags = fg_draw_list->Flags;
     10494                            fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
     10495                            fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255,255,0,255), true, 1.0f);
     10496                            fg_draw_list->Flags = backup_flags;
     10497                        }
     10498                    }
     10499                ImGui::TreePop();
    1337410500            }
    1337510501            ImGui::TreePop();
    13376          }
    13377 
    13378          static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
    13379          {
     10502        }
     10503
     10504        static void NodeColumns(const ImGuiColumns* columns)
     10505        {
     10506            if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
     10507                return;
     10508            ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
     10509            for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
     10510                ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
     10511            ImGui::TreePop();
     10512        }
     10513
     10514        static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
     10515        {
    1338010516            if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size))
    13381                return;
    13382             for (int i = 0; i < windows.Size; i++)
    13383                Funcs::NodeWindow(windows[i], "Window");
     10517                return;
     10518            ImGui::Text("(In front-to-back order:)");
     10519            for (int i = windows.Size - 1; i >= 0; i--) // Iterate front to back
     10520            {
     10521                ImGui::PushID(windows[i]);
     10522                Funcs::NodeWindow(windows[i], "Window");
     10523                ImGui::PopID();
     10524            }
    1338410525            ImGui::TreePop();
    13385          }
    13386 
    13387          static void NodeWindow(ImGuiWindow* window, const char* label)
    13388          {
    13389             if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window))
    13390                return;
     10526        }
     10527
     10528        static void NodeWindow(ImGuiWindow* window, const char* label)
     10529        {
     10530            if (window == NULL)
     10531            {
     10532                ImGui::BulletText("%s: NULL", label);
     10533                return;
     10534            }
     10535
     10536            ImGuiContext& g = *GImGui;
     10537            const bool is_active = window->WasActive;
     10538            ImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None;
     10539            if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
     10540            const bool open = ImGui::TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*");
     10541            if (!is_active) { PopStyleColor(); }
     10542            if (ImGui::IsItemHovered() && is_active)
     10543                ImGui::GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
     10544            if (!open)
     10545                return;
     10546
     10547            if (window->MemoryCompacted)
     10548                ImGui::TextDisabled("Note: some memory buffers have been compacted/freed.");
     10549
    1339110550            ImGuiWindowFlags flags = window->Flags;
    1339210551            NodeDrawList(window, window->DrawList, "DrawList");
    13393             ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
    13394             ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s..)", flags,
    13395                (flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
    13396                (flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "");
    13397             ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetScrollMaxX(window), window->Scroll.y, GetScrollMaxY(window));
    13398             ImGui::BulletText("Active: %d, WriteAccessed: %d", window->Active, window->WriteAccessed);
     10552            ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y);
     10553            ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
     10554                (flags & ImGuiWindowFlags_ChildWindow)  ? "Child " : "",      (flags & ImGuiWindowFlags_Tooltip)     ? "Tooltip "   : "",  (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
     10555                (flags & ImGuiWindowFlags_Modal)        ? "Modal " : "",      (flags & ImGuiWindowFlags_ChildMenu)   ? "ChildMenu " : "",  (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
     10556                (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
     10557            ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
     10558            ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
     10559            ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
    1339910560            ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
    1340010561            ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
    1340110562            if (!window->NavRectRel[0].IsInverted())
    13402                ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
     10563                ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
    1340310564            else
    13404                ImGui::BulletText("NavRectRel[0]: <None>");
     10565                ImGui::BulletText("NavRectRel[0]: <None>");
    1340510566            if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
    1340610567            if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow");
     
    1340810569            if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
    1340910570            {
    13410                for (int n = 0; n < window->ColumnsStorage.Size; n++)
    13411                {
    13412                   const ImGuiColumnsSet* columns = &window->ColumnsStorage[n];
    13413                   if (ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
    13414                   {
    13415                      ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX);
    13416                      for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
    13417                         ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm));
    13418                      ImGui::TreePop();
    13419                   }
    13420                }
    13421                ImGui::TreePop();
     10571                for (int n = 0; n < window->ColumnsStorage.Size; n++)
     10572                    NodeColumns(&window->ColumnsStorage[n]);
     10573                ImGui::TreePop();
    1342210574            }
    13423             ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));
     10575            NodeStorage(&window->StateStorage, "Storage");
    1342410576            ImGui::TreePop();
    13425          }
    13426       };
    13427 
    13428       // Access private state, we are going to display the draw lists from last frame
    13429       ImGuiContext& g = *GImGui;
    13430       Funcs::NodeWindows(g.Windows, "Windows");
    13431       if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
    13432       {
    13433          for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
     10577        }
     10578
     10579        static void NodeWindowSettings(ImGuiWindowSettings* settings)
     10580        {
     10581            ImGui::Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
     10582                settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
     10583        }
     10584
     10585        static void NodeTabBar(ImGuiTabBar* tab_bar)
     10586        {
     10587            // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.
     10588            char buf[256];
     10589            char* p = buf;
     10590            const char* buf_end = buf + IM_ARRAYSIZE(buf);
     10591            const bool is_active = (tab_bar->PrevFrameVisible >= ImGui::GetFrameCount() - 2);
     10592            p += ImFormatString(p, buf_end - p, "Tab Bar 0x%08X (%d tabs)%s", tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
     10593            IM_UNUSED(p);
     10594            if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
     10595            bool open = ImGui::TreeNode(tab_bar, "%s", buf);
     10596            if (!is_active) { PopStyleColor(); }
     10597            if (is_active && ImGui::IsItemHovered())
     10598            {
     10599                ImDrawList* draw_list = ImGui::GetForegroundDrawList();
     10600                draw_list->AddRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max, IM_COL32(255, 255, 0, 255));
     10601                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));
     10602                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));
     10603            }
     10604            if (open)
     10605            {
     10606                for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
     10607                {
     10608                    const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
     10609                    ImGui::PushID(tab);
     10610                    if (ImGui::SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } ImGui::SameLine(0, 2);
     10611                    if (ImGui::SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } ImGui::SameLine();
     10612                    ImGui::Text("%02d%c Tab 0x%08X '%s' Offset: %.1f, Width: %.1f/%.1f", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "", tab->Offset, tab->Width, tab->ContentWidth);
     10613                    ImGui::PopID();
     10614                }
     10615                ImGui::TreePop();
     10616            }
     10617        }
     10618
     10619        static void NodeStorage(ImGuiStorage* storage, const char* label)
     10620        {
     10621            if (!ImGui::TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
     10622                return;
     10623            for (int n = 0; n < storage->Data.Size; n++)
     10624            {
     10625                const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
     10626                ImGui::BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
     10627            }
     10628            ImGui::TreePop();
     10629        }
     10630    };
     10631
     10632    // Tools
     10633    if (ImGui::TreeNode("Tools"))
     10634    {
     10635        // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
     10636        if (ImGui::Button("Item Picker.."))
     10637            ImGui::DebugStartItemPicker();
     10638        ImGui::SameLine();
     10639        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.");
     10640
     10641        ImGui::Checkbox("Show windows begin order", &show_windows_begin_order);
     10642        ImGui::Checkbox("Show windows rectangles", &show_windows_rects);
     10643        ImGui::SameLine();
     10644        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
     10645        show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count, WRT_Count);
     10646        if (show_windows_rects && g.NavWindow)
     10647        {
     10648            ImGui::BulletText("'%s':", g.NavWindow->Name);
     10649            ImGui::Indent();
     10650            for (int rect_n = 0; rect_n < WRT_Count; rect_n++)
     10651            {
     10652                ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n);
     10653                ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]);
     10654            }
     10655            ImGui::Unindent();
     10656        }
     10657        ImGui::Checkbox("Show mesh when hovering ImDrawCmd", &show_drawcmd_mesh);
     10658        ImGui::Checkbox("Show bounding boxes when hovering ImDrawCmd", &show_drawcmd_aabb);
     10659        ImGui::TreePop();
     10660    }
     10661
     10662    // Contents
     10663    Funcs::NodeWindows(g.Windows, "Windows");
     10664    //Funcs::NodeWindows(g.WindowsFocusOrder, "WindowsFocusOrder");
     10665    if (ImGui::TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
     10666    {
     10667        for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
    1343410668            Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList");
    13435          ImGui::TreePop();
    13436       }
    13437       if (ImGui::TreeNode("Popups", "Open Popups Stack (%d)", g.OpenPopupStack.Size))
    13438       {
    13439          for (int i = 0; i < g.OpenPopupStack.Size; i++)
    13440          {
     10669        ImGui::TreePop();
     10670    }
     10671
     10672    // Details for Popups
     10673    if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
     10674    {
     10675        for (int i = 0; i < g.OpenPopupStack.Size; i++)
     10676        {
    1344110677            ImGuiWindow* window = g.OpenPopupStack[i].Window;
    1344210678            ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : "");
    13443          }
    13444          ImGui::TreePop();
    13445       }
    13446       if (ImGui::TreeNode("Internal state"))
    13447       {
    13448          const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
    13449          ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
    13450          ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
    13451          ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec)", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
    13452          ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), ActiveIdSource: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, input_source_names[g.ActiveIdSource]);
    13453          ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
    13454          ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
    13455          ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
    13456          ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
    13457          ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
    13458          ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
    13459          ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
    13460          ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
    13461          ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
    13462          ImGui::TreePop();
    13463       }
    13464    }
    13465    ImGui::End();
    13466 }
     10679        }
     10680        ImGui::TreePop();
     10681    }
     10682
     10683    // Details for TabBars
     10684    if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
     10685    {
     10686        for (int n = 0; n < g.TabBars.GetSize(); n++)
     10687            Funcs::NodeTabBar(g.TabBars.GetByIndex(n));
     10688        ImGui::TreePop();
     10689    }
     10690
     10691    // Details for Tables
     10692    IM_UNUSED(trt_rects_names);
     10693    IM_UNUSED(show_tables_rects);
     10694    IM_UNUSED(show_tables_rect_type);
     10695#ifdef IMGUI_HAS_TABLE
     10696    if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
     10697    {
     10698        for (int n = 0; n < g.Tables.GetSize(); n++)
     10699            Funcs::NodeTable(g.Tables.GetByIndex(n));
     10700        ImGui::TreePop();
     10701    }
     10702#endif // #ifdef IMGUI_HAS_TABLE
     10703
     10704    // Details for Docking
     10705#ifdef IMGUI_HAS_DOCK
     10706    if (ImGui::TreeNode("Dock nodes"))
     10707    {
     10708        ImGui::TreePop();
     10709    }
     10710#endif // #ifdef IMGUI_HAS_DOCK
     10711
     10712    // Settings
     10713    if (ImGui::TreeNode("Settings"))
     10714    {
     10715        if (ImGui::SmallButton("Clear"))
     10716            ImGui::ClearIniSettings();
     10717        ImGui::SameLine();
     10718        if (ImGui::SmallButton("Save to memory"))
     10719            ImGui::SaveIniSettingsToMemory();
     10720        ImGui::SameLine();
     10721        if (ImGui::SmallButton("Save to disk"))
     10722            ImGui::SaveIniSettingsToDisk(g.IO.IniFilename);
     10723        ImGui::SameLine();
     10724        if (g.IO.IniFilename)
     10725            ImGui::Text("\"%s\"", g.IO.IniFilename);
     10726        else
     10727            ImGui::TextUnformatted("<NULL>");
     10728        ImGui::Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
     10729        if (ImGui::TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
     10730        {
     10731            for (int n = 0; n < g.SettingsHandlers.Size; n++)
     10732                ImGui::BulletText("%s", g.SettingsHandlers[n].TypeName);
     10733            ImGui::TreePop();
     10734        }
     10735        if (ImGui::TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
     10736        {
     10737            for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
     10738                Funcs::NodeWindowSettings(settings);
     10739            ImGui::TreePop();
     10740        }
     10741
     10742#ifdef IMGUI_HAS_TABLE
     10743        if (ImGui::TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
     10744        {
     10745            for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
     10746                Funcs::NodeTableSettings(settings);
     10747            ImGui::TreePop();
     10748        }
     10749#endif // #ifdef IMGUI_HAS_TABLE
     10750
     10751#ifdef IMGUI_HAS_DOCK
     10752#endif // #ifdef IMGUI_HAS_DOCK
     10753
     10754        if (ImGui::TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size()))
     10755        {
     10756            ImGui::InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, 0.0f), ImGuiInputTextFlags_ReadOnly);
     10757            ImGui::TreePop();
     10758        }
     10759        ImGui::TreePop();
     10760    }
     10761
     10762    // Misc Details
     10763    if (ImGui::TreeNode("Internal state"))
     10764    {
     10765        const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
     10766
     10767        ImGui::Text("WINDOWING");
     10768        ImGui::Indent();
     10769        ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
     10770        ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
     10771        ImGui::Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL");
     10772        ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
     10773        ImGui::Unindent();
     10774
     10775        ImGui::Text("ITEMS");
     10776        ImGui::Indent();
     10777        ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]);
     10778        ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
     10779        ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
     10780        ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
     10781        ImGui::Unindent();
     10782
     10783        ImGui::Text("NAV,FOCUS");
     10784        ImGui::Indent();
     10785        ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
     10786        ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
     10787        ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
     10788        ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
     10789        ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
     10790        ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
     10791        ImGui::Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
     10792        ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
     10793        ImGui::Unindent();
     10794
     10795        ImGui::TreePop();
     10796    }
     10797
     10798    // Overlay: Display windows Rectangles and Begin Order
     10799    if (show_windows_rects || show_windows_begin_order)
     10800    {
     10801        for (int n = 0; n < g.Windows.Size; n++)
     10802        {
     10803            ImGuiWindow* window = g.Windows[n];
     10804            if (!window->WasActive)
     10805                continue;
     10806            ImDrawList* draw_list = GetForegroundDrawList(window);
     10807            if (show_windows_rects)
     10808            {
     10809                ImRect r = Funcs::GetWindowRect(window, show_windows_rect_type);
     10810                draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
     10811            }
     10812            if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow))
     10813            {
     10814                char buf[32];
     10815                ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
     10816                float font_size = ImGui::GetFontSize();
     10817                draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
     10818                draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf);
     10819            }
     10820        }
     10821    }
     10822
     10823#ifdef IMGUI_HAS_TABLE
     10824    // Overlay: Display Tables Rectangles
     10825    if (show_tables_rects)
     10826    {
     10827        for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
     10828        {
     10829            ImGuiTable* table = g.Tables.GetByIndex(table_n);
     10830        }
     10831    }
     10832#endif // #ifdef IMGUI_HAS_TABLE
     10833
     10834#ifdef IMGUI_HAS_DOCK
     10835    // Overlay: Display Docking info
     10836    if (show_docking_nodes && g.IO.KeyCtrl)
     10837    {
     10838    }
     10839#endif // #ifdef IMGUI_HAS_DOCK
     10840
     10841    ImGui::End();
     10842}
     10843
     10844#else
     10845
     10846void ImGui::ShowMetricsWindow(bool*) { }
     10847
     10848#endif
    1346710849
    1346810850//-----------------------------------------------------------------------------
     
    1347510857
    1347610858//-----------------------------------------------------------------------------
     10859
     10860#endif // #ifndef IMGUI_DISABLE
Note: See TracChangeset for help on using the changeset viewer.