Changeset e66fd66 in opengl-game


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

Files:
8 added
4 deleted
8 edited
3 moved

Legend:

Unmodified
Added
Removed
  • .gitignore

    r78c3045 re66fd66  
    1616*.opendb
    1717.vs/
    18 *.filters
    1918*.dll
    2019Debug/
  • 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
  • IMGUI/imgui.h

    r78c3045 re66fd66  
    1 // dear imgui, v1.61 WIP
     1// dear imgui, v1.79
    22// (headers)
    33
    4 // See imgui.cpp file for documentation.
    5 // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
    6 // Read 'Programmer guide' in imgui.cpp for notes on how to setup ImGui in your codebase.
    7 // Get latest version at https://github.com/ocornut/imgui
     4// Help:
     5// - Read FAQ at http://dearimgui.org/faq
     6// - Newcomers, read 'Programmer guide' in imgui.cpp 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
     19/*
     20
     21Index of this file:
     22// Header mess
     23// Forward declarations and basic types
     24// ImGui API (Dear ImGui end-user API)
     25// Flags & Enumerations
     26// Memory allocations macros
     27// ImVector<>
     28// ImGuiStyle
     29// ImGuiIO
     30// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload)
     31// Obsolete functions
     32// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor)
     33// Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
     34// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
     35
     36*/
    837
    938#pragma once
    1039
    11 #define IMGUI_DISABLE_INCLUDE_IMCONFIG_H
    12 
    13 // Configuration file (edit imconfig.h or define IMGUI_USER_CONFIG to set your own filename)
     40// Configuration file with compile-time options (edit imconfig.h or #define IMGUI_USER_CONFIG to your own filename)
    1441#ifdef IMGUI_USER_CONFIG
    1542#include IMGUI_USER_CONFIG
     
    1946#endif
    2047
    21 #include <float.h>                  // FLT_MAX
    22 #include <stdarg.h>                 // va_list
     48#ifndef IMGUI_DISABLE
     49
     50//-----------------------------------------------------------------------------
     51// Header mess
     52//-----------------------------------------------------------------------------
     53
     54// Includes
     55#include <float.h>                  // FLT_MIN, FLT_MAX
     56#include <stdarg.h>                 // va_list, va_start, va_end
    2357#include <stddef.h>                 // ptrdiff_t, NULL
    2458#include <string.h>                 // memset, memmove, memcpy, strlen, strchr, strcpy, strcmp
    2559
    2660// Version
    27 #define IMGUI_VERSION               "1.61 WIP"
    28 #define IMGUI_CHECKVERSION()        ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert))
     61// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
     62#define IMGUI_VERSION               "1.79"
     63#define IMGUI_VERSION_NUM           17900
     64#define IMGUI_CHECKVERSION()        ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
    2965
    3066// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
     67// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h)
     68// Using dear imgui via a shared library is not recommended, because we don't guarantee backward nor forward ABI compatibility (also function call overhead, as dear imgui is a call-heavy API)
    3169#ifndef IMGUI_API
    3270#define IMGUI_API
    3371#endif
    34 
    35 // Helpers
     72#ifndef IMGUI_IMPL_API
     73#define IMGUI_IMPL_API              IMGUI_API
     74#endif
     75
     76// Helper Macros
    3677#ifndef IM_ASSERT
    3778#include <assert.h>
    38 #define IM_ASSERT(_EXPR)            assert(_EXPR)
    39 #endif
    40 #if defined(__clang__) || defined(__GNUC__)
    41 #define IM_FMTARGS(FMT)             __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to user functions.
     79#define IM_ASSERT(_EXPR)            assert(_EXPR)                               // You can override the default assert handler by editing imconfig.h
     80#endif
     81#if !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__))
     82#define IM_FMTARGS(FMT)             __attribute__((format(printf, FMT, FMT+1))) // To apply printf-style warnings to our functions.
    4283#define IM_FMTLIST(FMT)             __attribute__((format(printf, FMT, 0)))
    4384#else
     
    4586#define IM_FMTLIST(FMT)
    4687#endif
    47 #define IM_ARRAYSIZE(_ARR)          ((int)(sizeof(_ARR)/sizeof(*_ARR)))         // Size of a static C-style array. Don't use on pointers!
    48 #define IM_OFFSETOF(_TYPE,_MEMBER)  ((size_t)&(((_TYPE*)0)->_MEMBER))           // Offset of _MEMBER within _TYPE. Standardized as offsetof() in modern C++.
    49 
     88#define IM_ARRAYSIZE(_ARR)          ((int)(sizeof(_ARR) / sizeof(*(_ARR))))     // Size of a static C-style array. Don't use on pointers!
     89#define IM_UNUSED(_VAR)             ((void)(_VAR))                              // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds.
     90#if (__cplusplus >= 201100)
     91#define IM_OFFSETOF(_TYPE,_MEMBER)  offsetof(_TYPE, _MEMBER)                    // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11
     92#else
     93#define IM_OFFSETOF(_TYPE,_MEMBER)  ((size_t)&(((_TYPE*)0)->_MEMBER))           // Offset of _MEMBER within _TYPE. Old style macro.
     94#endif
     95
     96// Warnings
    5097#if defined(__clang__)
    5198#pragma clang diagnostic push
    5299#pragma clang diagnostic ignored "-Wold-style-cast"
    53 #endif
     100#if __has_warning("-Wzero-as-null-pointer-constant")
     101#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
     102#endif
     103#elif defined(__GNUC__)
     104#pragma GCC diagnostic push
     105#pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
     106#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
     107#endif
     108
     109//-----------------------------------------------------------------------------
     110// Forward declarations and basic types
     111//-----------------------------------------------------------------------------
    54112
    55113// Forward declarations
    56 struct ImDrawChannel;               // Temporary storage for outputting drawing commands out of order, used by ImDrawList::ChannelsSplit()
    57 struct ImDrawCmd;                   // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call)
    58 struct ImDrawData;                  // All draw command lists required to render the frame
    59 struct ImDrawList;                  // A single draw command list (generally one per window)
     114struct ImDrawChannel;               // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit()
     115struct ImDrawCmd;                   // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback)
     116struct ImDrawData;                  // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix.
     117struct ImDrawList;                  // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder)
    60118struct ImDrawListSharedData;        // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself)
    61 struct ImDrawVert;                  // A single vertex (20 bytes by default, override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT)
     119struct ImDrawListSplitter;          // Helper to split a draw list into different layers which can be drawn into out of order, then flattened back.
     120struct ImDrawVert;                  // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT)
    62121struct ImFont;                      // Runtime data for a single font within a parent ImFontAtlas
    63122struct ImFontAtlas;                 // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader
    64123struct ImFontConfig;                // Configuration data when adding a font or merging fonts
    65 struct ImColor;                     // Helper functions to create a color that can be converted to either u32 or float4 (*obsolete* please avoid using)
     124struct ImFontGlyph;                 // A single font glyph (code point + coordinates within in ImFontAtlas + offset)
     125struct ImFontGlyphRangesBuilder;    // Helper to build glyph ranges from text/string data
     126struct ImColor;                     // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using)
     127struct ImGuiContext;                // Dear ImGui context (opaque structure, unless including imgui_internal.h)
    66128struct ImGuiIO;                     // Main configuration and I/O between your application and ImGui
    67 struct ImGuiOnceUponAFrame;         // Simple helper for running a block of code not more than once a frame, used by IMGUI_ONCE_UPON_A_FRAME macro
    68 struct ImGuiStorage;                // Simple custom key value storage
     129struct ImGuiInputTextCallbackData;  // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use)
     130struct ImGuiListClipper;            // Helper to manually clip large list of items
     131struct ImGuiOnceUponAFrame;         // Helper for running a block of code not more than once a frame, used by IMGUI_ONCE_UPON_A_FRAME macro
     132struct ImGuiPayload;                // User data payload for drag and drop operations
     133struct ImGuiSizeCallbackData;       // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use)
     134struct ImGuiStorage;                // Helper for key->value storage
    69135struct ImGuiStyle;                  // Runtime data for styling/colors
    70 struct ImGuiTextFilter;             // Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
    71 struct ImGuiTextBuffer;             // Text buffer for logging/accumulating text
    72 struct ImGuiTextEditCallbackData;   // Shared state of ImGui::InputText() when using custom ImGuiTextEditCallback (rare/advanced use)
    73 struct ImGuiSizeCallbackData;       // Structure used to constraint window size in custom ways when using custom ImGuiSizeCallback (rare/advanced use)
    74 struct ImGuiListClipper;            // Helper to manually clip large list of items
    75 struct ImGuiPayload;                // User data payload for drag and drop operations
    76 struct ImGuiContext;                // ImGui context (opaque)
    77 
    78 #ifndef ImTextureID
    79 typedef void* ImTextureID;          // User data to identify a texture (this is whatever to you want it to be! read the FAQ about ImTextureID in imgui.cpp)
    80 #endif
    81 
    82                                     // Typedefs and Enumerations (declared as int for compatibility with old C++ and to not pollute the top of this file)
    83 typedef unsigned int ImU32;         // 32-bit unsigned integer (typically used to store packed colors)
    84 typedef unsigned int ImGuiID;       // Unique ID used by widgets (typically hashed from a stack of string)
    85 typedef unsigned short ImWchar;     // Character for keyboard input/display
    86 typedef int ImGuiCol;               // enum: a color identifier for styling     // enum ImGuiCol_
    87 typedef int ImGuiDir;               // enum: a cardinal direction               // enum ImGuiDir_
    88 typedef int ImGuiCond;              // enum: a condition for Set*()             // enum ImGuiCond_
    89 typedef int ImGuiKey;               // enum: a key identifier (ImGui-side enum) // enum ImGuiKey_
    90 typedef int ImGuiNavInput;          // enum: an input identifier for navigation // enum ImGuiNavInput_
    91 typedef int ImGuiMouseCursor;       // enum: a mouse cursor identifier          // enum ImGuiMouseCursor_
    92 typedef int ImGuiStyleVar;          // enum: a variable identifier for styling  // enum ImGuiStyleVar_
    93 typedef int ImDrawCornerFlags;      // flags: for ImDrawList::AddRect*() etc.   // enum ImDrawCornerFlags_
    94 typedef int ImDrawListFlags;        // flags: for ImDrawList                    // enum ImDrawListFlags_
    95 typedef int ImFontAtlasFlags;       // flags: for ImFontAtlas                   // enum ImFontAtlasFlags_
    96 typedef int ImGuiBackendFlags;      // flags: for io.BackendFlags               // enum ImGuiBackendFlags_
    97 typedef int ImGuiColorEditFlags;    // flags: for ColorEdit*(), ColorPicker*()  // enum ImGuiColorEditFlags_
    98 typedef int ImGuiColumnsFlags;      // flags: for *Columns*()                   // enum ImGuiColumnsFlags_
    99 typedef int ImGuiConfigFlags;       // flags: for io.ConfigFlags                // enum ImGuiConfigFlags_
    100 typedef int ImGuiDragDropFlags;     // flags: for *DragDrop*()                  // enum ImGuiDragDropFlags_
    101 typedef int ImGuiComboFlags;        // flags: for BeginCombo()                  // enum ImGuiComboFlags_
    102 typedef int ImGuiFocusedFlags;      // flags: for IsWindowFocused()             // enum ImGuiFocusedFlags_
    103 typedef int ImGuiHoveredFlags;      // flags: for IsItemHovered() etc.          // enum ImGuiHoveredFlags_
    104 typedef int ImGuiInputTextFlags;    // flags: for InputText*()                  // enum ImGuiInputTextFlags_
    105 typedef int ImGuiSelectableFlags;   // flags: for Selectable()                  // enum ImGuiSelectableFlags_
    106 typedef int ImGuiTreeNodeFlags;     // flags: for TreeNode*(),CollapsingHeader()// enum ImGuiTreeNodeFlags_
    107 typedef int ImGuiWindowFlags;       // flags: for Begin*()                      // enum ImGuiWindowFlags_
    108 typedef int(*ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data);
    109 typedef void(*ImGuiSizeCallback)(ImGuiSizeCallbackData* data);
     136struct ImGuiTextBuffer;             // Helper to hold and append into a text buffer (~string builder)
     137struct ImGuiTextFilter;             // Helper to parse and apply text filters (e.g. "aaaaa[,bbbbb][,ccccc]")
     138
     139// Enums/Flags (declared as int for compatibility with old C++, to allow using as flags and to not pollute the top of this file)
     140// - Tip: Use your programming IDE navigation facilities on the names in the _central column_ below to find the actual flags/enum lists!
     141//   In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
     142//   With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
     143typedef int ImGuiCol;               // -> enum ImGuiCol_             // Enum: A color identifier for styling
     144typedef int ImGuiCond;              // -> enum ImGuiCond_            // Enum: A condition for many Set*() functions
     145typedef int ImGuiDataType;          // -> enum ImGuiDataType_        // Enum: A primary data type
     146typedef int ImGuiDir;               // -> enum ImGuiDir_             // Enum: A cardinal direction
     147typedef int ImGuiKey;               // -> enum ImGuiKey_             // Enum: A key identifier (ImGui-side enum)
     148typedef int ImGuiNavInput;          // -> enum ImGuiNavInput_        // Enum: An input identifier for navigation
     149typedef int ImGuiMouseButton;       // -> enum ImGuiMouseButton_     // Enum: A mouse button identifier (0=left, 1=right, 2=middle)
     150typedef int ImGuiMouseCursor;       // -> enum ImGuiMouseCursor_     // Enum: A mouse cursor identifier
     151typedef int ImGuiStyleVar;          // -> enum ImGuiStyleVar_        // Enum: A variable identifier for styling
     152typedef int ImDrawCornerFlags;      // -> enum ImDrawCornerFlags_    // Flags: for ImDrawList::AddRect(), AddRectFilled() etc.
     153typedef int ImDrawListFlags;        // -> enum ImDrawListFlags_      // Flags: for ImDrawList
     154typedef int ImFontAtlasFlags;       // -> enum ImFontAtlasFlags_     // Flags: for ImFontAtlas build
     155typedef int ImGuiBackendFlags;      // -> enum ImGuiBackendFlags_    // Flags: for io.BackendFlags
     156typedef int ImGuiButtonFlags;       // -> enum ImGuiButtonFlags_     // Flags: for InvisibleButton()
     157typedef int ImGuiColorEditFlags;    // -> enum ImGuiColorEditFlags_  // Flags: for ColorEdit4(), ColorPicker4() etc.
     158typedef int ImGuiConfigFlags;       // -> enum ImGuiConfigFlags_     // Flags: for io.ConfigFlags
     159typedef int ImGuiComboFlags;        // -> enum ImGuiComboFlags_      // Flags: for BeginCombo()
     160typedef int ImGuiDragDropFlags;     // -> enum ImGuiDragDropFlags_   // Flags: for BeginDragDropSource(), AcceptDragDropPayload()
     161typedef int ImGuiFocusedFlags;      // -> enum ImGuiFocusedFlags_    // Flags: for IsWindowFocused()
     162typedef int ImGuiHoveredFlags;      // -> enum ImGuiHoveredFlags_    // Flags: for IsItemHovered(), IsWindowHovered() etc.
     163typedef int ImGuiInputTextFlags;    // -> enum ImGuiInputTextFlags_  // Flags: for InputText(), InputTextMultiline()
     164typedef int ImGuiKeyModFlags;       // -> enum ImGuiKeyModFlags_     // Flags: for io.KeyMods (Ctrl/Shift/Alt/Super)
     165typedef int ImGuiPopupFlags;        // -> enum ImGuiPopupFlags_      // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen()
     166typedef int ImGuiSelectableFlags;   // -> enum ImGuiSelectableFlags_ // Flags: for Selectable()
     167typedef int ImGuiSliderFlags;       // -> enum ImGuiSliderFlags_     // Flags: for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc.
     168typedef int ImGuiTabBarFlags;       // -> enum ImGuiTabBarFlags_     // Flags: for BeginTabBar()
     169typedef int ImGuiTabItemFlags;      // -> enum ImGuiTabItemFlags_    // Flags: for BeginTabItem()
     170typedef int ImGuiTreeNodeFlags;     // -> enum ImGuiTreeNodeFlags_   // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader()
     171typedef int ImGuiWindowFlags;       // -> enum ImGuiWindowFlags_     // Flags: for Begin(), BeginChild()
     172
     173// Other types
     174#ifndef ImTextureID                 // ImTextureID [configurable type: override in imconfig.h with '#define ImTextureID xxx']
     175typedef void* ImTextureID;          // User data for rendering back-end to identify a texture. This is whatever to you want it to be! read the FAQ about ImTextureID for details.
     176#endif
     177typedef unsigned int ImGuiID;       // A unique ID used by widgets, typically hashed from a stack of string.
     178typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data);
     179typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data);
     180
     181// Decoded character types
     182// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)
     183typedef unsigned short ImWchar16;   // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings.
     184typedef unsigned int ImWchar32;     // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.
     185#ifdef IMGUI_USE_WCHAR32            // ImWchar [configurable type: override in imconfig.h with '#define IMGUI_USE_WCHAR32' to support Unicode planes 1-16]
     186typedef ImWchar32 ImWchar;
     187#else
     188typedef ImWchar16 ImWchar;
     189#endif
     190
     191// Basic scalar data types
     192typedef signed char         ImS8;   // 8-bit signed integer
     193typedef unsigned char       ImU8;   // 8-bit unsigned integer
     194typedef signed short        ImS16;  // 16-bit signed integer
     195typedef unsigned short      ImU16;  // 16-bit unsigned integer
     196typedef signed int          ImS32;  // 32-bit signed integer == int
     197typedef unsigned int        ImU32;  // 32-bit unsigned integer (often used to store packed colors)
    110198#if defined(_MSC_VER) && !defined(__clang__)
    111 typedef unsigned __int64 ImU64;     // 64-bit unsigned integer
     199typedef signed   __int64    ImS64;  // 64-bit signed integer (pre and post C++11 with Visual Studio)
     200typedef unsigned __int64    ImU64;  // 64-bit unsigned integer (pre and post C++11 with Visual Studio)
     201#elif (defined(__clang__) || defined(__GNUC__)) && (__cplusplus < 201100)
     202#include <stdint.h>
     203typedef int64_t             ImS64;  // 64-bit signed integer (pre C++11)
     204typedef uint64_t            ImU64;  // 64-bit unsigned integer (pre C++11)
    112205#else
    113 typedef unsigned long long ImU64;   // 64-bit unsigned integer
    114 #endif
    115 
     206typedef signed   long long  ImS64;  // 64-bit signed integer (post C++11)
     207typedef unsigned long long  ImU64;  // 64-bit unsigned integer (post C++11)
     208#endif
     209
     210// 2D vector (often used to store positions or sizes)
    116211struct ImVec2
    117212{
    118    float     x, y;
    119    ImVec2() { x = y = 0.0f; }
    120    ImVec2(float _x, float _y) { x = _x; y = _y; }
    121    float operator[] (size_t i) const { IM_ASSERT(i <= 1); return (&x)[i]; }    // We very rarely use this [] operator, the assert overhead is fine.
     213    float                                   x, y;
     214    ImVec2()                                { x = y = 0.0f; }
     215    ImVec2(float _x, float _y)              { x = _x; y = _y; }
     216    float  operator[] (size_t idx) const    { IM_ASSERT(idx <= 1); return (&x)[idx]; }    // We very rarely use this [] operator, the assert overhead is fine.
     217    float& operator[] (size_t idx)          { IM_ASSERT(idx <= 1); return (&x)[idx]; }    // We very rarely use this [] operator, the assert overhead is fine.
    122218#ifdef IM_VEC2_CLASS_EXTRA
    123    IM_VEC2_CLASS_EXTRA     // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2.
    124 #endif
    125 };
    126 
     219    IM_VEC2_CLASS_EXTRA     // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec2.
     220#endif
     221};
     222
     223// 4D vector (often used to store floating-point colors)
    127224struct ImVec4
    128225{
    129    float     x, y, z, w;
    130    ImVec4() { x = y = z = w = 0.0f; }
    131    ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; }
     226    float                                   x, y, z, w;
     227    ImVec4()                                { x = y = z = w = 0.0f; }
     228    ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; }
    132229#ifdef IM_VEC4_CLASS_EXTRA
    133    IM_VEC4_CLASS_EXTRA     // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4.
    134 #endif
    135 };
    136 
    137 // ImGui end-user API
    138 // In a namespace so that user can add extra functions in your own separate file (please don't modify imgui.cpp/.h)
     230    IM_VEC4_CLASS_EXTRA     // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4.
     231#endif
     232};
     233
     234//-----------------------------------------------------------------------------
     235// ImGui: Dear ImGui end-user API
     236// (This is a namespace. You can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!)
     237//-----------------------------------------------------------------------------
     238
    139239namespace ImGui
    140240{
    141    // Context creation and access
    142    // All contexts share a same ImFontAtlas by default. If you want different font atlas, you can new() them and overwrite the GetIO().Fonts variable of an ImGui context.
    143    // All those functions are not reliant on the current context.
    144    IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL);
    145    IMGUI_API void          DestroyContext(ImGuiContext* ctx = NULL);   // NULL = destroy current context
    146    IMGUI_API ImGuiContext* GetCurrentContext();
    147    IMGUI_API void          SetCurrentContext(ImGuiContext* ctx);
    148    IMGUI_API bool          DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert);
    149 
    150    // Main
    151    IMGUI_API ImGuiIO&      GetIO();
    152    IMGUI_API ImGuiStyle&   GetStyle();
    153    IMGUI_API void          NewFrame();                                 // start a new ImGui frame, you can submit any command from this point until Render()/EndFrame().
    154    IMGUI_API void          Render();                                   // ends the ImGui frame, finalize the draw data. (Obsolete: optionally call io.RenderDrawListsFn if set. Nowadays, prefer calling your render function yourself.)
    155    IMGUI_API ImDrawData*   GetDrawData();                              // valid after Render() and until the next call to NewFrame(). this is what you have to render. (Obsolete: this used to be passed to your io.RenderDrawListsFn() function.)
    156    IMGUI_API void          EndFrame();                                 // ends the ImGui frame. automatically called by Render(), so most likely don't need to ever call that yourself directly. If you don't need to render you may call EndFrame() but you'll have wasted CPU already. If you don't need to render, better to not create any imgui windows instead!
    157 
    158                                                                        // Demo, Debug, Information
    159    IMGUI_API void          ShowDemoWindow(bool* p_open = NULL);        // create demo/test window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
    160    IMGUI_API void          ShowMetricsWindow(bool* p_open = NULL);     // create metrics window. display ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc.
    161    IMGUI_API void          ShowStyleEditor(ImGuiStyle* ref = NULL);    // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style)
    162    IMGUI_API bool          ShowStyleSelector(const char* label);       // add style selector block (not a window), essentially a combo listing the default styles.
    163    IMGUI_API void          ShowFontSelector(const char* label);        // add font selector block (not a window), essentially a combo listing the loaded fonts.
    164    IMGUI_API void          ShowUserGuide();                            // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls).
    165    IMGUI_API const char*   GetVersion();                               // get a version string e.g. "1.23"
    166 
    167                                                                        // Styles
    168    IMGUI_API void          StyleColorsDark(ImGuiStyle* dst = NULL);    // new, recommended style (default)
    169    IMGUI_API void          StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style
    170    IMGUI_API void          StyleColorsLight(ImGuiStyle* dst = NULL);   // best used with borders and a custom, thicker font
    171 
    172                                                                        // Windows
    173                                                                        // (Begin = push window to the stack and start appending to it. End = pop window from the stack. You may append multiple times to the same window during the same frame)
    174                                                                        // Begin()/BeginChild() return false to indicate the window being collapsed or fully clipped, so you may early out and omit submitting anything to the window.
    175                                                                        // However you need to always call a matching End()/EndChild() for a Begin()/BeginChild() call, regardless of its return value (this is due to legacy reason and is inconsistent with BeginMenu/EndMenu, BeginPopup/EndPopup and other functions where the End call should only be called if the corresponding Begin function returned true.)
    176                                                                        // Passing 'bool* p_open != NULL' shows a close widget in the upper-right corner of the window, which when clicking will set the boolean to false.
    177                                                                        // Use child windows to introduce independent scrolling/clipping regions within a host window. Child windows can embed their own child.
    178    IMGUI_API bool          Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
    179    IMGUI_API void          End();
    180    IMGUI_API bool          BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0); // Begin a scrolling region. size==0.0f: use remaining window size, size<0.0f: use remaining window size minus abs(size). size>0.0f: fixed size. each axis can use a different mode, e.g. ImVec2(0,400).
    181    IMGUI_API bool          BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0);
    182    IMGUI_API void          EndChild();
    183 
    184    // Windows Utilities
    185    IMGUI_API bool          IsWindowAppearing();
    186    IMGUI_API bool          IsWindowCollapsed();
    187    IMGUI_API bool          IsWindowFocused(ImGuiFocusedFlags flags = 0); // is current window focused? or its root/child, depending on flags. see flags for options.
    188    IMGUI_API bool          IsWindowHovered(ImGuiHoveredFlags flags = 0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ!
    189    IMGUI_API ImDrawList*   GetWindowDrawList();                        // get draw list associated to the window, to append your own drawing primitives
    190    IMGUI_API ImVec2        GetWindowPos();                             // get current window position in screen space (useful if you want to do your own drawing via the DrawList API)
    191    IMGUI_API ImVec2        GetWindowSize();                            // get current window size
    192    IMGUI_API float         GetWindowWidth();                           // get current window width (shortcut for GetWindowSize().x)
    193    IMGUI_API float         GetWindowHeight();                          // get current window height (shortcut for GetWindowSize().y)
    194    IMGUI_API ImVec2        GetContentRegionMax();                      // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates
    195    IMGUI_API ImVec2        GetContentRegionAvail();                    // == GetContentRegionMax() - GetCursorPos()
    196    IMGUI_API float         GetContentRegionAvailWidth();               //
    197    IMGUI_API ImVec2        GetWindowContentRegionMin();                // content boundaries min (roughly (0,0)-Scroll), in window coordinates
    198    IMGUI_API ImVec2        GetWindowContentRegionMax();                // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates
    199    IMGUI_API float         GetWindowContentRegionWidth();              //
    200 
    201    IMGUI_API void          SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc.
    202    IMGUI_API void          SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0);                  // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin()
    203    IMGUI_API void          SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Use callback to apply non-trivial programmatic constraints.
    204    IMGUI_API void          SetNextWindowContentSize(const ImVec2& size);                               // set next window content size (~ enforce the range of scrollbars). not including window decorations (title bar, menu bar, etc.). set an axis to 0.0f to leave it automatic. call before Begin()
    205    IMGUI_API void          SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0);                 // set next window collapsed state. call before Begin()
    206    IMGUI_API void          SetNextWindowFocus();                                                       // set next window to be focused / front-most. call before Begin()
    207    IMGUI_API void          SetNextWindowBgAlpha(float alpha);                                          // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg.
    208    IMGUI_API void          SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0);                        // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects.
    209    IMGUI_API void          SetWindowSize(const ImVec2& size, ImGuiCond cond = 0);                      // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.   
    210    IMGUI_API void          SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0);                     // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
    211    IMGUI_API void          SetWindowFocus();                                                           // (not recommended) set current window to be focused / front-most. prefer using SetNextWindowFocus().
    212    IMGUI_API void          SetWindowFontScale(float scale);                                            // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows
    213    IMGUI_API void          SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0);      // set named window position.
    214    IMGUI_API void          SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0);    // set named window size. set axis to 0.0f to force an auto-fit on this axis.
    215    IMGUI_API void          SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0);   // set named window collapsed state
    216    IMGUI_API void          SetWindowFocus(const char* name);                                           // set named window to be focused / front-most. use NULL to remove focus.
    217 
    218                                                                                                        // Windows Scrolling
    219    IMGUI_API float         GetScrollX();                                                   // get scrolling amount [0..GetScrollMaxX()]
    220    IMGUI_API float         GetScrollY();                                                   // get scrolling amount [0..GetScrollMaxY()]
    221    IMGUI_API float         GetScrollMaxX();                                                // get maximum scrolling amount ~~ ContentSize.X - WindowSize.X
    222    IMGUI_API float         GetScrollMaxY();                                                // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y
    223    IMGUI_API void          SetScrollX(float scroll_x);                                     // set scrolling amount [0..GetScrollMaxX()]
    224    IMGUI_API void          SetScrollY(float scroll_y);                                     // set scrolling amount [0..GetScrollMaxY()]
    225    IMGUI_API void          SetScrollHere(float center_y_ratio = 0.5f);                     // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
    226    IMGUI_API void          SetScrollFromPosY(float pos_y, float center_y_ratio = 0.5f);    // adjust scrolling amount to make given position valid. use GetCursorPos() or GetCursorStartPos()+offset to get valid positions.
    227 
    228                                                                                            // Parameters stacks (shared)
    229    IMGUI_API void          PushFont(ImFont* font);                                         // use NULL as a shortcut to push default font
    230    IMGUI_API void          PopFont();
    231    IMGUI_API void          PushStyleColor(ImGuiCol idx, ImU32 col);
    232    IMGUI_API void          PushStyleColor(ImGuiCol idx, const ImVec4& col);
    233    IMGUI_API void          PopStyleColor(int count = 1);
    234    IMGUI_API void          PushStyleVar(ImGuiStyleVar idx, float val);
    235    IMGUI_API void          PushStyleVar(ImGuiStyleVar idx, const ImVec2& val);
    236    IMGUI_API void          PopStyleVar(int count = 1);
    237    IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx);                                // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in.
    238    IMGUI_API ImFont*       GetFont();                                                      // get current font
    239    IMGUI_API float         GetFontSize();                                                  // get current font size (= height in pixels) of current font with current scale applied
    240    IMGUI_API ImVec2        GetFontTexUvWhitePixel();                                       // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API
    241    IMGUI_API ImU32         GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f);              // retrieve given style color with style alpha applied and optional extra alpha multiplier
    242    IMGUI_API ImU32         GetColorU32(const ImVec4& col);                                 // retrieve given color with style alpha applied
    243    IMGUI_API ImU32         GetColorU32(ImU32 col);                                         // retrieve given color with style alpha applied
    244 
    245                                                                                            // Parameters stacks (current window)
    246    IMGUI_API void          PushItemWidth(float item_width);                                // width of items for the common item+label case, pixels. 0.0f = default to ~2/3 of windows width, >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side)
    247    IMGUI_API void          PopItemWidth();
    248    IMGUI_API float         CalcItemWidth();                                                // width of item given pushed settings and current cursor position
    249    IMGUI_API void          PushTextWrapPos(float wrap_pos_x = 0.0f);                       // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space
    250    IMGUI_API void          PopTextWrapPos();
    251    IMGUI_API void          PushAllowKeyboardFocus(bool allow_keyboard_focus);              // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
    252    IMGUI_API void          PopAllowKeyboardFocus();
    253    IMGUI_API void          PushButtonRepeat(bool repeat);                                  // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame.
    254    IMGUI_API void          PopButtonRepeat();
    255 
    256    // Cursor / Layout
    257    IMGUI_API void          Separator();                                                    // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator.
    258    IMGUI_API void          SameLine(float pos_x = 0.0f, float spacing_w = -1.0f);          // call between widgets or groups to layout them horizontally
    259    IMGUI_API void          NewLine();                                                      // undo a SameLine()
    260    IMGUI_API void          Spacing();                                                      // add vertical spacing
    261    IMGUI_API void          Dummy(const ImVec2& size);                                      // add a dummy item of given size
    262    IMGUI_API void          Indent(float indent_w = 0.0f);                                  // move content position toward the right, by style.IndentSpacing or indent_w if != 0
    263    IMGUI_API void          Unindent(float indent_w = 0.0f);                                // move content position back to the left, by style.IndentSpacing or indent_w if != 0
    264    IMGUI_API void          BeginGroup();                                                   // 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.)
    265    IMGUI_API void          EndGroup();
    266    IMGUI_API ImVec2        GetCursorPos();                                                 // cursor position is relative to window position
    267    IMGUI_API float         GetCursorPosX();                                                // "
    268    IMGUI_API float         GetCursorPosY();                                                // "
    269    IMGUI_API void          SetCursorPos(const ImVec2& local_pos);                          // "
    270    IMGUI_API void          SetCursorPosX(float x);                                         // "
    271    IMGUI_API void          SetCursorPosY(float y);                                         // "
    272    IMGUI_API ImVec2        GetCursorStartPos();                                            // initial cursor position
    273    IMGUI_API ImVec2        GetCursorScreenPos();                                           // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API)
    274    IMGUI_API void          SetCursorScreenPos(const ImVec2& screen_pos);                   // cursor position in absolute screen coordinates [0..io.DisplaySize]
    275    IMGUI_API void          AlignTextToFramePadding();                                      // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item)
    276    IMGUI_API float         GetTextLineHeight();                                            // ~ FontSize
    277    IMGUI_API float         GetTextLineHeightWithSpacing();                                 // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text)
    278    IMGUI_API float         GetFrameHeight();                                               // ~ FontSize + style.FramePadding.y * 2
    279    IMGUI_API float         GetFrameHeightWithSpacing();                                    // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets)
    280 
    281                                                                                            // ID stack/scopes
    282                                                                                            // Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most
    283                                                                                            // likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.
    284                                                                                            // You can also use the "##foobar" syntax within widget label to distinguish them from each others.
    285                                                                                            // In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID,
    286                                                                                            // whereas "str_id" denote a string that is only used as an ID and not aimed to be displayed.
    287    IMGUI_API void          PushID(const char* str_id);                                     // push identifier into the ID stack. IDs are hash of the entire stack!
    288    IMGUI_API void          PushID(const char* str_id_begin, const char* str_id_end);
    289    IMGUI_API void          PushID(const void* ptr_id);
    290    IMGUI_API void          PushID(int int_id);
    291    IMGUI_API void          PopID();
    292    IMGUI_API ImGuiID       GetID(const char* str_id);                                      // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself
    293    IMGUI_API ImGuiID       GetID(const char* str_id_begin, const char* str_id_end);
    294    IMGUI_API ImGuiID       GetID(const void* ptr_id);
    295 
    296    // Widgets: Text
    297    IMGUI_API void          TextUnformatted(const char* text, const char* text_end = NULL);                // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text.
    298    IMGUI_API void          Text(const char* fmt, ...)                                      IM_FMTARGS(1); // simple formatted text
    299    IMGUI_API void          TextV(const char* fmt, va_list args)                            IM_FMTLIST(1);
    300    IMGUI_API void          TextColored(const ImVec4& col, const char* fmt, ...)            IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor();
    301    IMGUI_API void          TextColoredV(const ImVec4& col, const char* fmt, va_list args)  IM_FMTLIST(2);
    302    IMGUI_API void          TextDisabled(const char* fmt, ...)                              IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor();
    303    IMGUI_API void          TextDisabledV(const char* fmt, va_list args)                    IM_FMTLIST(1);
    304    IMGUI_API void          TextWrapped(const char* fmt, ...)                               IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize().
    305    IMGUI_API void          TextWrappedV(const char* fmt, va_list args)                     IM_FMTLIST(1);
    306    IMGUI_API void          LabelText(const char* label, const char* fmt, ...)              IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets
    307    IMGUI_API void          LabelTextV(const char* label, const char* fmt, va_list args)    IM_FMTLIST(2);
    308    IMGUI_API void          BulletText(const char* fmt, ...)                                IM_FMTARGS(1); // shortcut for Bullet()+Text()
    309    IMGUI_API void          BulletTextV(const char* fmt, va_list args)                      IM_FMTLIST(1);
    310 
    311    // Widgets: Main
    312    IMGUI_API bool          Button(const char* label, const ImVec2& size = ImVec2(0, 0));    // button
    313    IMGUI_API bool          SmallButton(const char* label);                                 // button with FramePadding=(0,0) to easily embed within text
    314    IMGUI_API bool          ArrowButton(const char* str_id, ImGuiDir dir);
    315    IMGUI_API bool          InvisibleButton(const char* str_id, const ImVec2& size);        // button behavior without the visuals, useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.)
    316    IMGUI_API void          Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), const ImVec4& tint_col = ImVec4(1, 1, 1, 1), const ImVec4& border_col = ImVec4(0, 0, 0, 0));
    317    IMGUI_API bool          ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1));    // <0 frame_padding uses default frame padding settings. 0 for no padding
    318    IMGUI_API bool          Checkbox(const char* label, bool* v);
    319    IMGUI_API bool          CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value);
    320    IMGUI_API bool          RadioButton(const char* label, bool active);
    321    IMGUI_API bool          RadioButton(const char* label, int* v, int v_button);
    322    IMGUI_API void          PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
    323    IMGUI_API void          PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
    324    IMGUI_API void          PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
    325    IMGUI_API void          PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
    326    IMGUI_API void          ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1, 0), const char* overlay = NULL);
    327    IMGUI_API void          Bullet();                                                       // draw a small circle and keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses
    328 
    329                                                                                            // Widgets: Combo Box
    330                                                                                            // The new BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it.
    331                                                                                            // The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose.
    332    IMGUI_API bool          BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0);
    333    IMGUI_API void          EndCombo(); // only call EndCombo() if BeginCombo() returns true!
    334    IMGUI_API bool          Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1);
    335    IMGUI_API bool          Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1);      // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0"
    336    IMGUI_API bool          Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1);
    337 
    338    // Widgets: Drags (tip: ctrl+click on a drag box to input with keyboard. manually input values aren't clamped, can go off-bounds)
    339    // For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x
    340    // Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision).
    341    IMGUI_API bool          DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);     // If v_min >= v_max we have no bound
    342    IMGUI_API bool          DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
    343    IMGUI_API bool          DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
    344    IMGUI_API bool          DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
    345    IMGUI_API bool          DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, float power = 1.0f);
    346    IMGUI_API bool          DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f");                                       // If v_min >= v_max we have no bound
    347    IMGUI_API bool          DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f");
    348    IMGUI_API bool          DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f");
    349    IMGUI_API bool          DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f");
    350    IMGUI_API bool          DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%.0f", const char* format_max = NULL);
    351 
    352    // Widgets: Input with Keyboard
    353    IMGUI_API bool          InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
    354    IMGUI_API bool          InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
    355    IMGUI_API bool          InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0);
    356    IMGUI_API bool          InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0);
    357    IMGUI_API bool          InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0);
    358    IMGUI_API bool          InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags extra_flags = 0);
    359    IMGUI_API bool          InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags extra_flags = 0);
    360    IMGUI_API bool          InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags = 0);
    361    IMGUI_API bool          InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags = 0);
    362    IMGUI_API bool          InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags = 0);
    363    IMGUI_API bool          InputDouble(const char* label, double* v, double step = 0.0f, double step_fast = 0.0f, const char* format = "%.6f", ImGuiInputTextFlags extra_flags = 0);
    364 
    365    // Widgets: Sliders (tip: ctrl+click on a slider to input with keyboard. manually input values aren't clamped, can go off-bounds)
    366    IMGUI_API bool          SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);     // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display. Use power!=1.0 for logarithmic sliders
    367    IMGUI_API bool          SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
    368    IMGUI_API bool          SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
    369    IMGUI_API bool          SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
    370    IMGUI_API bool          SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f);
    371    IMGUI_API bool          SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%.0f");
    372    IMGUI_API bool          SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%.0f");
    373    IMGUI_API bool          SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%.0f");
    374    IMGUI_API bool          SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%.0f");
    375    IMGUI_API bool          VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
    376    IMGUI_API bool          VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%.0f");
    377 
    378    // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.)
    379    // Note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can the pass the address of a first float element out of a contiguous structure, e.g. &myvector.x
    380    IMGUI_API bool          ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0);
    381    IMGUI_API bool          ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0);
    382    IMGUI_API bool          ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0);
    383    IMGUI_API bool          ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL);
    384    IMGUI_API bool          ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0));  // display a colored square/button, hover for details, return true when pressed.
    385    IMGUI_API void          SetColorEditOptions(ImGuiColorEditFlags flags);                     // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls.
    386 
    387                                                                                                // Widgets: Trees
    388    IMGUI_API bool          TreeNode(const char* label);                                        // if returning 'true' the node is open and the tree id is pushed into the id stack. user is responsible for calling TreePop().
    389    IMGUI_API bool          TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2);   // read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet().
    390    IMGUI_API bool          TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2);   // "
    391    IMGUI_API bool          TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2);
    392    IMGUI_API bool          TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2);
    393    IMGUI_API bool          TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0);
    394    IMGUI_API bool          TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3);
    395    IMGUI_API bool          TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3);
    396    IMGUI_API bool          TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3);
    397    IMGUI_API bool          TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3);
    398    IMGUI_API void          TreePush(const char* str_id);                                       // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call Push/Pop yourself for layout purpose
    399    IMGUI_API void          TreePush(const void* ptr_id = NULL);                                // "
    400    IMGUI_API void          TreePop();                                                          // ~ Unindent()+PopId()
    401    IMGUI_API void          TreeAdvanceToLabelPos();                                            // advance cursor x position by GetTreeNodeToLabelSpacing()
    402    IMGUI_API float         GetTreeNodeToLabelSpacing();                                        // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode
    403    IMGUI_API void          SetNextTreeNodeOpen(bool is_open, ImGuiCond cond = 0);              // set next TreeNode/CollapsingHeader open state.
    404    IMGUI_API bool          CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0);  // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop().
    405    IMGUI_API bool          CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header
    406 
    407                                                                                                             // Widgets: Selectable / Lists
    408    IMGUI_API bool          Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0));  // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height
    409    IMGUI_API bool          Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0));       // "bool* p_selected" point to the selection state (read-write), as a convenient helper.
    410    IMGUI_API bool          ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1);
    411    IMGUI_API bool          ListBox(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
    412    IMGUI_API bool          ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards.
    413    IMGUI_API bool          ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // "
    414    IMGUI_API void          ListBoxFooter();                                                    // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true!
    415 
    416                                                                                                // Widgets: Value() Helpers. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace)
    417    IMGUI_API void          Value(const char* prefix, bool b);
    418    IMGUI_API void          Value(const char* prefix, int v);
    419    IMGUI_API void          Value(const char* prefix, unsigned int v);
    420    IMGUI_API void          Value(const char* prefix, float v, const char* float_format = NULL);
    421 
    422    // Tooltips
    423    IMGUI_API void          SetTooltip(const char* fmt, ...) IM_FMTARGS(1);                     // set text tooltip under mouse-cursor, typically use with ImGui::IsItemHovered(). overidde any previous call to SetTooltip().
    424    IMGUI_API void          SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1);
    425    IMGUI_API void          BeginTooltip();                                                     // begin/append a tooltip window. to create full-featured tooltip (with any kind of contents).
    426    IMGUI_API void          EndTooltip();
    427 
    428    // Menus
    429    IMGUI_API bool          BeginMainMenuBar();                                                 // create and append to a full screen menu-bar.
    430    IMGUI_API void          EndMainMenuBar();                                                   // only call EndMainMenuBar() if BeginMainMenuBar() returns true!
    431    IMGUI_API bool          BeginMenuBar();                                                     // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window).
    432    IMGUI_API void          EndMenuBar();                                                       // only call EndMenuBar() if BeginMenuBar() returns true!
    433    IMGUI_API bool          BeginMenu(const char* label, bool enabled = true);                  // create a sub-menu entry. only call EndMenu() if this returns true!
    434    IMGUI_API void          EndMenu();                                                          // only call EndMenu() if BeginMenu() returns true!
    435    IMGUI_API bool          MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true);  // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment
    436    IMGUI_API bool          MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true);              // return true when activated + toggle (*p_selected) if p_selected != NULL
    437 
    438                                                                                                                                   // Popups
    439    IMGUI_API void          OpenPopup(const char* str_id);                                      // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
    440    IMGUI_API bool          BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0);                                             // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returns true!
    441    IMGUI_API bool          BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1);                                 // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!
    442    IMGUI_API bool          BeginPopupContextWindow(const char* str_id = NULL, int mouse_button = 1, bool also_over_items = true);  // helper to open and begin popup when clicked on current window.
    443    IMGUI_API bool          BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1);                                 // helper to open and begin popup when clicked in void (where there are no imgui windows).
    444    IMGUI_API bool          BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);                     // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside)
    445    IMGUI_API void          EndPopup();                                                                                             // only call EndPopup() if BeginPopupXXX() returns true!
    446    IMGUI_API bool          OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1);                                  // helper to open popup when clicked on last item. return true when just opened.
    447    IMGUI_API bool          IsPopupOpen(const char* str_id);                                    // return true if the popup is open
    448    IMGUI_API void          CloseCurrentPopup();                                                // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup.
    449 
    450                                                                                                // Columns
    451                                                                                                // You can also use SameLine(pos_x) for simplified columns. The columns API is still work-in-progress and rather lacking.
    452    IMGUI_API void          Columns(int count = 1, const char* id = NULL, bool border = true);
    453    IMGUI_API void          NextColumn();                                                       // next column, defaults to current row or next row if the current row is finished
    454    IMGUI_API int           GetColumnIndex();                                                   // get current column index
    455    IMGUI_API float         GetColumnWidth(int column_index = -1);                              // get column width (in pixels). pass -1 to use current column
    456    IMGUI_API void          SetColumnWidth(int column_index, float width);                      // set column width (in pixels). pass -1 to use current column
    457    IMGUI_API float         GetColumnOffset(int column_index = -1);                             // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f
    458    IMGUI_API void          SetColumnOffset(int column_index, float offset_x);                  // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column
    459    IMGUI_API int           GetColumnsCount();
    460 
    461    // Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging.
    462    IMGUI_API void          LogToTTY(int max_depth = -1);                                       // start logging to tty
    463    IMGUI_API void          LogToFile(int max_depth = -1, const char* filename = NULL);         // start logging to file
    464    IMGUI_API void          LogToClipboard(int max_depth = -1);                                 // start logging to OS clipboard
    465    IMGUI_API void          LogFinish();                                                        // stop logging (close file, etc.)
    466    IMGUI_API void          LogButtons();                                                       // helper to display buttons for logging to tty/file/clipboard
    467    IMGUI_API void          LogText(const char* fmt, ...) IM_FMTARGS(1);                        // pass text data straight to log (without being displayed)
    468 
    469                                                                                                // Drag and Drop
    470                                                                                                // [BETA API] Missing Demo code. API may evolve.
    471    IMGUI_API bool          BeginDragDropSource(ImGuiDragDropFlags flags = 0);                                      // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource()
    472    IMGUI_API bool          SetDragDropPayload(const char* type, const void* data, size_t size, ImGuiCond cond = 0);// type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui.
    473    IMGUI_API void          EndDragDropSource();                                                                    // only call EndDragDropSource() if BeginDragDropSource() returns true!
    474    IMGUI_API bool          BeginDragDropTarget();                                                                  // call after submitting an item that may receive an item. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget()
    475    IMGUI_API const ImGuiPayload* AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0);            // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released.
    476    IMGUI_API void          EndDragDropTarget();                                                                    // only call EndDragDropTarget() if BeginDragDropTarget() returns true!
    477 
    478                                                                                                                    // Clipping
    479    IMGUI_API void          PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect);
    480    IMGUI_API void          PopClipRect();
    481 
    482    // Focus, Activation
    483    // (Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHere()" when applicable, to make your code more forward compatible when navigation branch is merged)
    484    IMGUI_API void          SetItemDefaultFocus();                                              // make last item the default focused item of a window. Please use instead of "if (IsWindowAppearing()) SetScrollHere()" to signify "default item".
    485    IMGUI_API void          SetKeyboardFocusHere(int offset = 0);                               // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget.
    486 
    487                                                                                                // Utilities
    488    IMGUI_API bool          IsItemHovered(ImGuiHoveredFlags flags = 0);                         // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options.
    489    IMGUI_API bool          IsItemActive();                                                     // is the last item active? (e.g. button being held, text field being edited- items that don't interact will always return false)
    490    IMGUI_API bool          IsItemFocused();                                                    // is the last item focused for keyboard/gamepad navigation?
    491    IMGUI_API bool          IsItemClicked(int mouse_button = 0);                                // is the last item clicked? (e.g. button/node just clicked on)
    492    IMGUI_API bool          IsItemVisible();                                                    // is the last item visible? (aka not out of sight due to clipping/scrolling.)
    493    IMGUI_API bool          IsAnyItemHovered();
    494    IMGUI_API bool          IsAnyItemActive();
    495    IMGUI_API bool          IsAnyItemFocused();
    496    IMGUI_API ImVec2        GetItemRectMin();                                                   // get bounding rectangle of last item, in screen space
    497    IMGUI_API ImVec2        GetItemRectMax();                                                   // "
    498    IMGUI_API ImVec2        GetItemRectSize();                                                  // get size of last item, in screen space
    499    IMGUI_API void          SetItemAllowOverlap();                                              // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area.
    500    IMGUI_API bool          IsRectVisible(const ImVec2& size);                                  // test if rectangle (of given size, starting from cursor position) is visible / not clipped.
    501    IMGUI_API bool          IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max);      // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side.
    502    IMGUI_API float         GetTime();
    503    IMGUI_API int           GetFrameCount();
    504    IMGUI_API ImDrawList*   GetOverlayDrawList();                                               // this draw list will be the last rendered one, useful to quickly draw overlays shapes/text
    505    IMGUI_API ImDrawListSharedData* GetDrawListSharedData();                                    // you may use this when creating your own ImDrawList instances
    506    IMGUI_API const char*   GetStyleColorName(ImGuiCol idx);
    507    IMGUI_API void          SetStateStorage(ImGuiStorage* storage);                             // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it)
    508    IMGUI_API ImGuiStorage* GetStateStorage();
    509    IMGUI_API ImVec2        CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f);
    510    IMGUI_API void          CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end);    // calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can.
    511 
    512    IMGUI_API bool          BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame
    513    IMGUI_API void          EndChildFrame();                                                    // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window)
    514 
    515    IMGUI_API ImVec4        ColorConvertU32ToFloat4(ImU32 in);
    516    IMGUI_API ImU32         ColorConvertFloat4ToU32(const ImVec4& in);
    517    IMGUI_API void          ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v);
    518    IMGUI_API void          ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b);
    519 
    520    // Inputs
    521    IMGUI_API int           GetKeyIndex(ImGuiKey imgui_key);                                    // map ImGuiKey_* values into user's key index. == io.KeyMap[key]
    522    IMGUI_API bool          IsKeyDown(int user_key_index);                                      // is key being held. == io.KeysDown[user_key_index]. note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your backend/engine stored them into io.KeysDown[]!
    523    IMGUI_API bool          IsKeyPressed(int user_key_index, bool repeat = true);               // was key pressed (went from !Down to Down). if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate
    524    IMGUI_API bool          IsKeyReleased(int user_key_index);                                  // was key released (went from Down to !Down)..
    525    IMGUI_API int           GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate
    526    IMGUI_API bool          IsMouseDown(int button);                                            // is mouse button held
    527    IMGUI_API bool          IsAnyMouseDown();                                                   // is any mouse button held
    528    IMGUI_API bool          IsMouseClicked(int button, bool repeat = false);                    // did mouse button clicked (went from !Down to Down)
    529    IMGUI_API bool          IsMouseDoubleClicked(int button);                                   // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime.
    530    IMGUI_API bool          IsMouseReleased(int button);                                        // did mouse button released (went from Down to !Down)
    531    IMGUI_API bool          IsMouseDragging(int button = 0, float lock_threshold = -1.0f);      // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold
    532    IMGUI_API bool          IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);  // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings. disregarding of consideration of focus/window ordering/blocked by a popup.
    533    IMGUI_API bool          IsMousePosValid(const ImVec2* mouse_pos = NULL);                    //
    534    IMGUI_API ImVec2        GetMousePos();                                                      // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls
    535    IMGUI_API ImVec2        GetMousePosOnOpeningCurrentPopup();                                 // retrieve backup of mouse position at the time of opening popup we have BeginPopup() into
    536    IMGUI_API ImVec2        GetMouseDragDelta(int button = 0, float lock_threshold = -1.0f);    // dragging amount since clicking. if lock_threshold < -1.0f uses io.MouseDraggingThreshold
    537    IMGUI_API void          ResetMouseDragDelta(int button = 0);                                //
    538    IMGUI_API ImGuiMouseCursor GetMouseCursor();                                                // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you
    539    IMGUI_API void          SetMouseCursor(ImGuiMouseCursor type);                              // set desired cursor type
    540    IMGUI_API void          CaptureKeyboardFromApp(bool capture = true);                        // manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered.
    541    IMGUI_API void          CaptureMouseFromApp(bool capture = true);                           // manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle).
    542 
    543                                                                                                // Clipboard Utilities (also see the LogToClipboard() function to capture or output text data to the clipboard)
    544    IMGUI_API const char*   GetClipboardText();
    545    IMGUI_API void          SetClipboardText(const char* text);
    546 
    547    // Memory Utilities
    548    // All those functions are not reliant on the current context.
    549    // If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again.
    550    IMGUI_API void          SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data = NULL);
    551    IMGUI_API void*         MemAlloc(size_t size);
    552    IMGUI_API void          MemFree(void* ptr);
     241    // Context creation and access
     242    // Each context create its own ImFontAtlas by default. You may instance one yourself and pass it to CreateContext() to share a font atlas between imgui contexts.
     243    // None of those functions is reliant on the current context.
     244    IMGUI_API ImGuiContext* CreateContext(ImFontAtlas* shared_font_atlas = NULL);
     245    IMGUI_API void          DestroyContext(ImGuiContext* ctx = NULL);   // NULL = destroy current context
     246    IMGUI_API ImGuiContext* GetCurrentContext();
     247    IMGUI_API void          SetCurrentContext(ImGuiContext* ctx);
     248
     249    // Main
     250    IMGUI_API ImGuiIO&      GetIO();                                    // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags)
     251    IMGUI_API ImGuiStyle&   GetStyle();                                 // access the Style structure (colors, sizes). Always use PushStyleCol(), PushStyleVar() to modify style mid-frame!
     252    IMGUI_API void          NewFrame();                                 // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame().
     253    IMGUI_API void          EndFrame();                                 // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all!
     254    IMGUI_API void          Render();                                   // ends the Dear ImGui frame, finalize the draw data. You can get call GetDrawData() to obtain it and run your rendering function (up to v1.60, this used to call io.RenderDrawListsFn(). Nowadays, we allow and prefer calling your render function yourself.)
     255    IMGUI_API ImDrawData*   GetDrawData();                              // valid after Render() and until the next call to NewFrame(). this is what you have to render.
     256
     257    // Demo, Debug, Information
     258    IMGUI_API void          ShowDemoWindow(bool* p_open = NULL);        // create Demo window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
     259    IMGUI_API void          ShowAboutWindow(bool* p_open = NULL);       // create About window. display Dear ImGui version, credits and build/system information.
     260    IMGUI_API void          ShowMetricsWindow(bool* p_open = NULL);     // create Debug/Metrics window. display Dear ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc.
     261    IMGUI_API void          ShowStyleEditor(ImGuiStyle* ref = NULL);    // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style)
     262    IMGUI_API bool          ShowStyleSelector(const char* label);       // add style selector block (not a window), essentially a combo listing the default styles.
     263    IMGUI_API void          ShowFontSelector(const char* label);        // add font selector block (not a window), essentially a combo listing the loaded fonts.
     264    IMGUI_API void          ShowUserGuide();                            // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls).
     265    IMGUI_API const char*   GetVersion();                               // get the compiled version string e.g. "1.23" (essentially the compiled value for IMGUI_VERSION)
     266
     267    // Styles
     268    IMGUI_API void          StyleColorsDark(ImGuiStyle* dst = NULL);    // new, recommended style (default)
     269    IMGUI_API void          StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style
     270    IMGUI_API void          StyleColorsLight(ImGuiStyle* dst = NULL);   // best used with borders and a custom, thicker font
     271
     272    // Windows
     273    // - Begin() = push window to the stack and start appending to it. End() = pop window from the stack.
     274    // - Passing 'bool* p_open != NULL' shows a window-closing widget in the upper-right corner of the window,
     275    //   which clicking will set the boolean to false when clicked.
     276    // - You may append multiple times to the same window during the same frame by calling Begin()/End() pairs multiple times.
     277    //   Some information such as 'flags' or 'p_open' will only be considered by the first call to Begin().
     278    // - Begin() return false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting
     279    //   anything to the window. Always call a matching End() for each Begin() call, regardless of its return value!
     280    //   [Important: due to legacy reason, this is inconsistent with most other functions such as BeginMenu/EndMenu,
     281    //    BeginPopup/EndPopup, etc. where the EndXXX call should only be called if the corresponding BeginXXX function
     282    //    returned true. Begin and BeginChild are the only odd ones out. Will be fixed in a future update.]
     283    // - Note that the bottom of window stack always contains a window called "Debug".
     284    IMGUI_API bool          Begin(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0);
     285    IMGUI_API void          End();
     286
     287    // Child Windows
     288    // - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child.
     289    // - For each independent axis of 'size': ==0.0f: use remaining host window size / >0.0f: fixed size / <0.0f: use remaining window size minus abs(size) / Each axis can use a different mode, e.g. ImVec2(0,400).
     290    // - BeginChild() returns false to indicate the window is collapsed or fully clipped, so you may early out and omit submitting anything to the window.
     291    //   Always call a matching EndChild() for each BeginChild() call, regardless of its return value [as with Begin: this is due to legacy reason and inconsistent with most BeginXXX functions apart from the regular Begin() which behaves like BeginChild().]
     292    IMGUI_API bool          BeginChild(const char* str_id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0);
     293    IMGUI_API bool          BeginChild(ImGuiID id, const ImVec2& size = ImVec2(0, 0), bool border = false, ImGuiWindowFlags flags = 0);
     294    IMGUI_API void          EndChild();
     295
     296    // Windows Utilities
     297    // - 'current window' = the window we are appending into while inside a Begin()/End() block. 'next window' = next window we will Begin() into.
     298    IMGUI_API bool          IsWindowAppearing();
     299    IMGUI_API bool          IsWindowCollapsed();
     300    IMGUI_API bool          IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options.
     301    IMGUI_API bool          IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ!
     302    IMGUI_API ImDrawList*   GetWindowDrawList();                        // get draw list associated to the current window, to append your own drawing primitives
     303    IMGUI_API ImVec2        GetWindowPos();                             // get current window position in screen space (useful if you want to do your own drawing via the DrawList API)
     304    IMGUI_API ImVec2        GetWindowSize();                            // get current window size
     305    IMGUI_API float         GetWindowWidth();                           // get current window width (shortcut for GetWindowSize().x)
     306    IMGUI_API float         GetWindowHeight();                          // get current window height (shortcut for GetWindowSize().y)
     307
     308    // Prefer using SetNextXXX functions (before Begin) rather that SetXXX functions (after Begin).
     309    IMGUI_API void          SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0, 0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc.
     310    IMGUI_API void          SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0);                  // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin()
     311    IMGUI_API void          SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints.
     312    IMGUI_API void          SetNextWindowContentSize(const ImVec2& size);                               // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin()
     313    IMGUI_API void          SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0);                 // set next window collapsed state. call before Begin()
     314    IMGUI_API void          SetNextWindowFocus();                                                       // set next window to be focused / top-most. call before Begin()
     315    IMGUI_API void          SetNextWindowBgAlpha(float alpha);                                          // set next window background color alpha. helper to easily override the Alpha component of ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground.
     316    IMGUI_API void          SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0);                        // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects.
     317    IMGUI_API void          SetWindowSize(const ImVec2& size, ImGuiCond cond = 0);                      // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0, 0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.
     318    IMGUI_API void          SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0);                     // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
     319    IMGUI_API void          SetWindowFocus();                                                           // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus().
     320    IMGUI_API void          SetWindowFontScale(float scale);                                            // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes().
     321    IMGUI_API void          SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0);      // set named window position.
     322    IMGUI_API void          SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0);    // set named window size. set axis to 0.0f to force an auto-fit on this axis.
     323    IMGUI_API void          SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0);   // set named window collapsed state
     324    IMGUI_API void          SetWindowFocus(const char* name);                                           // set named window to be focused / top-most. use NULL to remove focus.
     325
     326    // Content region
     327    // - Those functions are bound to be redesigned soon (they are confusing, incomplete and return values in local window coordinates which increases confusion)
     328    IMGUI_API ImVec2        GetContentRegionMax();                                          // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates
     329    IMGUI_API ImVec2        GetContentRegionAvail();                                        // == GetContentRegionMax() - GetCursorPos()
     330    IMGUI_API ImVec2        GetWindowContentRegionMin();                                    // content boundaries min (roughly (0,0)-Scroll), in window coordinates
     331    IMGUI_API ImVec2        GetWindowContentRegionMax();                                    // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates
     332    IMGUI_API float         GetWindowContentRegionWidth();                                  //
     333
     334    // Windows Scrolling
     335    IMGUI_API float         GetScrollX();                                                   // get scrolling amount [0..GetScrollMaxX()]
     336    IMGUI_API float         GetScrollY();                                                   // get scrolling amount [0..GetScrollMaxY()]
     337    IMGUI_API float         GetScrollMaxX();                                                // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x
     338    IMGUI_API float         GetScrollMaxY();                                                // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y
     339    IMGUI_API void          SetScrollX(float scroll_x);                                     // set scrolling amount [0..GetScrollMaxX()]
     340    IMGUI_API void          SetScrollY(float scroll_y);                                     // set scrolling amount [0..GetScrollMaxY()]
     341    IMGUI_API void          SetScrollHereX(float center_x_ratio = 0.5f);                    // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
     342    IMGUI_API void          SetScrollHereY(float center_y_ratio = 0.5f);                    // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
     343    IMGUI_API void          SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f);  // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position.
     344    IMGUI_API void          SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f);  // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position.
     345
     346    // Parameters stacks (shared)
     347    IMGUI_API void          PushFont(ImFont* font);                                         // use NULL as a shortcut to push default font
     348    IMGUI_API void          PopFont();
     349    IMGUI_API void          PushStyleColor(ImGuiCol idx, ImU32 col);
     350    IMGUI_API void          PushStyleColor(ImGuiCol idx, const ImVec4& col);
     351    IMGUI_API void          PopStyleColor(int count = 1);
     352    IMGUI_API void          PushStyleVar(ImGuiStyleVar idx, float val);
     353    IMGUI_API void          PushStyleVar(ImGuiStyleVar idx, const ImVec2& val);
     354    IMGUI_API void          PopStyleVar(int count = 1);
     355    IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx);                                // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in.
     356    IMGUI_API ImFont*       GetFont();                                                      // get current font
     357    IMGUI_API float         GetFontSize();                                                  // get current font size (= height in pixels) of current font with current scale applied
     358    IMGUI_API ImVec2        GetFontTexUvWhitePixel();                                       // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API
     359    IMGUI_API ImU32         GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f);              // retrieve given style color with style alpha applied and optional extra alpha multiplier
     360    IMGUI_API ImU32         GetColorU32(const ImVec4& col);                                 // retrieve given color with style alpha applied
     361    IMGUI_API ImU32         GetColorU32(ImU32 col);                                         // retrieve given color with style alpha applied
     362
     363    // Parameters stacks (current window)
     364    IMGUI_API void          PushItemWidth(float item_width);                                // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side). 0.0f = default to ~2/3 of windows width,
     365    IMGUI_API void          PopItemWidth();
     366    IMGUI_API void          SetNextItemWidth(float item_width);                             // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side)
     367    IMGUI_API float         CalcItemWidth();                                                // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions.
     368    IMGUI_API void          PushTextWrapPos(float wrap_local_pos_x = 0.0f);                 // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space
     369    IMGUI_API void          PopTextWrapPos();
     370    IMGUI_API void          PushAllowKeyboardFocus(bool allow_keyboard_focus);              // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
     371    IMGUI_API void          PopAllowKeyboardFocus();
     372    IMGUI_API void          PushButtonRepeat(bool repeat);                                  // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame.
     373    IMGUI_API void          PopButtonRepeat();
     374
     375    // Cursor / Layout
     376    // - By "cursor" we mean the current output position.
     377    // - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down.
     378    // - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget.
     379    // - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API:
     380    //    Window-local coordinates:   SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos()
     381    //    Absolute coordinate:        GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions.
     382    IMGUI_API void          Separator();                                                    // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator.
     383    IMGUI_API void          SameLine(float offset_from_start_x=0.0f, float spacing=-1.0f);  // call between widgets or groups to layout them horizontally. X position given in window coordinates.
     384    IMGUI_API void          NewLine();                                                      // undo a SameLine() or force a new line when in an horizontal-layout context.
     385    IMGUI_API void          Spacing();                                                      // add vertical spacing.
     386    IMGUI_API void          Dummy(const ImVec2& size);                                      // add a dummy item of given size. unlike InvisibleButton(), Dummy() won't take the mouse click or be navigable into.
     387    IMGUI_API void          Indent(float indent_w = 0.0f);                                  // move content position toward the right, by style.IndentSpacing or indent_w if != 0
     388    IMGUI_API void          Unindent(float indent_w = 0.0f);                                // move content position back to the left, by style.IndentSpacing or indent_w if != 0
     389    IMGUI_API void          BeginGroup();                                                   // lock horizontal starting position
     390    IMGUI_API void          EndGroup();                                                     // unlock horizontal starting position + capture the whole group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
     391    IMGUI_API ImVec2        GetCursorPos();                                                 // cursor position in window coordinates (relative to window position)
     392    IMGUI_API float         GetCursorPosX();                                                //   (some functions are using window-relative coordinates, such as: GetCursorPos, GetCursorStartPos, GetContentRegionMax, GetWindowContentRegion* etc.
     393    IMGUI_API float         GetCursorPosY();                                                //    other functions such as GetCursorScreenPos or everything in ImDrawList::
     394    IMGUI_API void          SetCursorPos(const ImVec2& local_pos);                          //    are using the main, absolute coordinate system.
     395    IMGUI_API void          SetCursorPosX(float local_x);                                   //    GetWindowPos() + GetCursorPos() == GetCursorScreenPos() etc.)
     396    IMGUI_API void          SetCursorPosY(float local_y);                                   //
     397    IMGUI_API ImVec2        GetCursorStartPos();                                            // initial cursor position in window coordinates
     398    IMGUI_API ImVec2        GetCursorScreenPos();                                           // cursor position in absolute screen coordinates [0..io.DisplaySize] (useful to work with ImDrawList API)
     399    IMGUI_API void          SetCursorScreenPos(const ImVec2& pos);                          // cursor position in absolute screen coordinates [0..io.DisplaySize]
     400    IMGUI_API void          AlignTextToFramePadding();                                      // vertically align upcoming text baseline to FramePadding.y so that it will align properly to regularly framed items (call if you have text on a line before a framed item)
     401    IMGUI_API float         GetTextLineHeight();                                            // ~ FontSize
     402    IMGUI_API float         GetTextLineHeightWithSpacing();                                 // ~ FontSize + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of text)
     403    IMGUI_API float         GetFrameHeight();                                               // ~ FontSize + style.FramePadding.y * 2
     404    IMGUI_API float         GetFrameHeightWithSpacing();                                    // ~ FontSize + style.FramePadding.y * 2 + style.ItemSpacing.y (distance in pixels between 2 consecutive lines of framed widgets)
     405
     406    // ID stack/scopes
     407    // - Read the FAQ for more details about how ID are handled in dear imgui. If you are creating widgets in a loop you most
     408    //   likely want to push a unique identifier (e.g. object pointer, loop index) to uniquely differentiate them.
     409    // - The resulting ID are hashes of the entire stack.
     410    // - You can also use the "Label##foobar" syntax within widget label to distinguish them from each others.
     411    // - In this header file we use the "label"/"name" terminology to denote a string that will be displayed and used as an ID,
     412    //   whereas "str_id" denote a string that is only used as an ID and not normally displayed.
     413    IMGUI_API void          PushID(const char* str_id);                                     // push string into the ID stack (will hash string).
     414    IMGUI_API void          PushID(const char* str_id_begin, const char* str_id_end);       // push string into the ID stack (will hash string).
     415    IMGUI_API void          PushID(const void* ptr_id);                                     // push pointer into the ID stack (will hash pointer).
     416    IMGUI_API void          PushID(int int_id);                                             // push integer into the ID stack (will hash integer).
     417    IMGUI_API void          PopID();                                                        // pop from the ID stack.
     418    IMGUI_API ImGuiID       GetID(const char* str_id);                                      // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself
     419    IMGUI_API ImGuiID       GetID(const char* str_id_begin, const char* str_id_end);
     420    IMGUI_API ImGuiID       GetID(const void* ptr_id);
     421
     422    // Widgets: Text
     423    IMGUI_API void          TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text.
     424    IMGUI_API void          Text(const char* fmt, ...)                                      IM_FMTARGS(1); // formatted text
     425    IMGUI_API void          TextV(const char* fmt, va_list args)                            IM_FMTLIST(1);
     426    IMGUI_API void          TextColored(const ImVec4& col, const char* fmt, ...)            IM_FMTARGS(2); // shortcut for PushStyleColor(ImGuiCol_Text, col); Text(fmt, ...); PopStyleColor();
     427    IMGUI_API void          TextColoredV(const ImVec4& col, const char* fmt, va_list args)  IM_FMTLIST(2);
     428    IMGUI_API void          TextDisabled(const char* fmt, ...)                              IM_FMTARGS(1); // shortcut for PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]); Text(fmt, ...); PopStyleColor();
     429    IMGUI_API void          TextDisabledV(const char* fmt, va_list args)                    IM_FMTLIST(1);
     430    IMGUI_API void          TextWrapped(const char* fmt, ...)                               IM_FMTARGS(1); // shortcut for PushTextWrapPos(0.0f); Text(fmt, ...); PopTextWrapPos();. Note that this won't work on an auto-resizing window if there's no other widgets to extend the window width, yoy may need to set a size using SetNextWindowSize().
     431    IMGUI_API void          TextWrappedV(const char* fmt, va_list args)                     IM_FMTLIST(1);
     432    IMGUI_API void          LabelText(const char* label, const char* fmt, ...)              IM_FMTARGS(2); // display text+label aligned the same way as value+label widgets
     433    IMGUI_API void          LabelTextV(const char* label, const char* fmt, va_list args)    IM_FMTLIST(2);
     434    IMGUI_API void          BulletText(const char* fmt, ...)                                IM_FMTARGS(1); // shortcut for Bullet()+Text()
     435    IMGUI_API void          BulletTextV(const char* fmt, va_list args)                      IM_FMTLIST(1);
     436
     437    // Widgets: Main
     438    // - Most widgets return true when the value has been changed or when pressed/selected
     439    // - You may also use one of the many IsItemXXX functions (e.g. IsItemActive, IsItemHovered, etc.) to query widget state.
     440    IMGUI_API bool          Button(const char* label, const ImVec2& size = ImVec2(0, 0));   // button
     441    IMGUI_API bool          SmallButton(const char* label);                                 // button with FramePadding=(0,0) to easily embed within text
     442    IMGUI_API bool          InvisibleButton(const char* str_id, const ImVec2& size, ImGuiButtonFlags flags = 0); // flexible button behavior without the visuals, frequently useful to build custom behaviors using the public api (along with IsItemActive, IsItemHovered, etc.)
     443    IMGUI_API bool          ArrowButton(const char* str_id, ImGuiDir dir);                  // square button with an arrow shape
     444    IMGUI_API void          Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1,1), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0));
     445    IMGUI_API bool          ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0),  const ImVec2& uv1 = ImVec2(1,1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0,0,0,0), const ImVec4& tint_col = ImVec4(1,1,1,1));    // <0 frame_padding uses default frame padding settings. 0 for no padding
     446    IMGUI_API bool          Checkbox(const char* label, bool* v);
     447    IMGUI_API bool          CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value);
     448    IMGUI_API bool          RadioButton(const char* label, bool active);                    // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; }
     449    IMGUI_API bool          RadioButton(const char* label, int* v, int v_button);           // shortcut to handle the above pattern when value is an integer
     450    IMGUI_API void          ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1, 0), const char* overlay = NULL);
     451    IMGUI_API void          Bullet();                                                       // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses
     452
     453    // Widgets: Combo Box
     454    // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items.
     455    // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose.
     456    IMGUI_API bool          BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0);
     457    IMGUI_API void          EndCombo(); // only call EndCombo() if BeginCombo() returns true!
     458    IMGUI_API bool          Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1);
     459    IMGUI_API bool          Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1);      // Separate items with \0 within a string, end item-list with \0\0. e.g. "One\0Two\0Three\0"
     460    IMGUI_API bool          Combo(const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1);
     461
     462    // Widgets: Drag Sliders
     463    // - CTRL+Click on any drag box to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
     464    // - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x
     465    // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
     466    // - Format string may also be set to NULL or use the default format ("%f" or "%d").
     467    // - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision).
     468    // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits.
     469    // - Use v_max = FLT_MAX / INT_MAX etc to avoid clamping to a maximum, same with v_min = -FLT_MAX / INT_MIN to avoid clamping to a minimum.
     470    // - We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them.
     471    // - Legacy: Pre-1.78 there are DragXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument.
     472    //   If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361
     473    IMGUI_API bool          DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0);     // If v_min >= v_max we have no bound
     474    IMGUI_API bool          DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
     475    IMGUI_API bool          DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
     476    IMGUI_API bool          DragFloat4(const char* label, float v[4], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
     477    IMGUI_API bool          DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", const char* format_max = NULL, ImGuiSliderFlags flags = 0);
     478    IMGUI_API bool          DragInt(const char* label, int* v, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0);  // If v_min >= v_max we have no bound
     479    IMGUI_API bool          DragInt2(const char* label, int v[2], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0);
     480    IMGUI_API bool          DragInt3(const char* label, int v[3], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0);
     481    IMGUI_API bool          DragInt4(const char* label, int v[4], float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", ImGuiSliderFlags flags = 0);
     482    IMGUI_API bool          DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed = 1.0f, int v_min = 0, int v_max = 0, const char* format = "%d", const char* format_max = NULL, ImGuiSliderFlags flags = 0);
     483    IMGUI_API bool          DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0);
     484    IMGUI_API bool          DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min = NULL, const void* p_max = NULL, const char* format = NULL, ImGuiSliderFlags flags = 0);
     485
     486    // Widgets: Regular Sliders
     487    // - CTRL+Click on any slider to turn them into an input box. Manually input values aren't clamped and can go off-bounds.
     488    // - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
     489    // - Format string may also be set to NULL or use the default format ("%f" or "%d").
     490    // - Legacy: Pre-1.78 there are SliderXXX() function signatures that takes a final `float power=1.0f' argument instead of the `ImGuiSliderFlags flags=0' argument.
     491    //   If you get a warning converting a float to ImGuiSliderFlags, read https://github.com/ocornut/imgui/issues/3361
     492    IMGUI_API bool          SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);     // adjust format to decorate the value with a prefix or a suffix for in-slider labels or unit display.
     493    IMGUI_API bool          SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
     494    IMGUI_API bool          SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
     495    IMGUI_API bool          SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
     496    IMGUI_API bool          SliderAngle(const char* label, float* v_rad, float v_degrees_min = -360.0f, float v_degrees_max = +360.0f, const char* format = "%.0f deg", ImGuiSliderFlags flags = 0);
     497    IMGUI_API bool          SliderInt(const char* label, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
     498    IMGUI_API bool          SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
     499    IMGUI_API bool          SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
     500    IMGUI_API bool          SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
     501    IMGUI_API bool          SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);
     502    IMGUI_API bool          SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);
     503    IMGUI_API bool          VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0);
     504    IMGUI_API bool          VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0);
     505    IMGUI_API bool          VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format = NULL, ImGuiSliderFlags flags = 0);
     506
     507    // Widgets: Input with Keyboard
     508    // - If you want to use InputText() with std::string or any custom dynamic string type, see misc/cpp/imgui_stdlib.h and comments in imgui_demo.cpp.
     509    // - Most of the ImGuiInputTextFlags flags are only useful for InputText() and not for InputFloatX, InputIntX, InputDouble etc.
     510    IMGUI_API bool          InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
     511    IMGUI_API bool          InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
     512    IMGUI_API bool          InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
     513    IMGUI_API bool          InputFloat(const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
     514    IMGUI_API bool          InputFloat2(const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
     515    IMGUI_API bool          InputFloat3(const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
     516    IMGUI_API bool          InputFloat4(const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0);
     517    IMGUI_API bool          InputInt(const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0);
     518    IMGUI_API bool          InputInt2(const char* label, int v[2], ImGuiInputTextFlags flags = 0);
     519    IMGUI_API bool          InputInt3(const char* label, int v[3], ImGuiInputTextFlags flags = 0);
     520    IMGUI_API bool          InputInt4(const char* label, int v[4], ImGuiInputTextFlags flags = 0);
     521    IMGUI_API bool          InputDouble(const char* label, double* v, double step = 0.0, double step_fast = 0.0, const char* format = "%.6f", ImGuiInputTextFlags flags = 0);
     522    IMGUI_API bool          InputScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);
     523    IMGUI_API bool          InputScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_step = NULL, const void* p_step_fast = NULL, const char* format = NULL, ImGuiInputTextFlags flags = 0);
     524
     525    // Widgets: Color Editor/Picker (tip: the ColorEdit* functions have a little colored preview square that can be left-clicked to open a picker, and right-clicked to open an option menu.)
     526    // - Note that in C++ a 'float v[X]' function argument is the _same_ as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible.
     527    // - You can pass the address of a first float element out of a contiguous structure, e.g. &myvector.x
     528    IMGUI_API bool          ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags = 0);
     529    IMGUI_API bool          ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0);
     530    IMGUI_API bool          ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags = 0);
     531    IMGUI_API bool          ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags = 0, const float* ref_col = NULL);
     532    IMGUI_API bool          ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0, 0)); // display a colored square/button, hover for details, return true when pressed.
     533    IMGUI_API void          SetColorEditOptions(ImGuiColorEditFlags flags);                     // initialize current options (generally on application startup) if you want to select a default format, picker type, etc. User will be able to change many settings, unless you pass the _NoOptions flag to your calls.
     534
     535    // Widgets: Trees
     536    // - TreeNode functions return true when the node is open, in which case you need to also call TreePop() when you are finished displaying the tree node contents.
     537    IMGUI_API bool          TreeNode(const char* label);
     538    IMGUI_API bool          TreeNode(const char* str_id, const char* fmt, ...) IM_FMTARGS(2);   // helper variation to easily decorelate the id from the displayed string. Read the FAQ about why and how to use ID. to align arbitrary text at the same level as a TreeNode() you can use Bullet().
     539    IMGUI_API bool          TreeNode(const void* ptr_id, const char* fmt, ...) IM_FMTARGS(2);   // "
     540    IMGUI_API bool          TreeNodeV(const char* str_id, const char* fmt, va_list args) IM_FMTLIST(2);
     541    IMGUI_API bool          TreeNodeV(const void* ptr_id, const char* fmt, va_list args) IM_FMTLIST(2);
     542    IMGUI_API bool          TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags = 0);
     543    IMGUI_API bool          TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3);
     544    IMGUI_API bool          TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...) IM_FMTARGS(3);
     545    IMGUI_API bool          TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3);
     546    IMGUI_API bool          TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args) IM_FMTLIST(3);
     547    IMGUI_API void          TreePush(const char* str_id);                                       // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired.
     548    IMGUI_API void          TreePush(const void* ptr_id = NULL);                                // "
     549    IMGUI_API void          TreePop();                                                          // ~ Unindent()+PopId()
     550    IMGUI_API float         GetTreeNodeToLabelSpacing();                                        // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode
     551    IMGUI_API bool          CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0);  // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop().
     552    IMGUI_API bool          CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header
     553    IMGUI_API void          SetNextItemOpen(bool is_open, ImGuiCond cond = 0);                  // set next TreeNode/CollapsingHeader open state.
     554
     555    // Widgets: Selectables
     556    // - A selectable highlights when hovered, and can display another color when selected.
     557    // - Neighbors selectable extend their highlight bounds in order to leave no gap between them. This is so a series of selected Selectable appear contiguous.
     558    IMGUI_API bool          Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height
     559    IMGUI_API bool          Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0));      // "bool* p_selected" point to the selection state (read-write), as a convenient helper.
     560
     561    // Widgets: List Boxes
     562    // - FIXME: To be consistent with all the newer API, ListBoxHeader/ListBoxFooter should in reality be called BeginListBox/EndListBox. Will rename them.
     563    IMGUI_API bool          ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1);
     564    IMGUI_API bool          ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1);
     565    IMGUI_API bool          ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards.
     566    IMGUI_API bool          ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // "
     567    IMGUI_API void          ListBoxFooter();                                                    // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true!
     568
     569    // Widgets: Data Plotting
     570    IMGUI_API void          PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
     571    IMGUI_API void          PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
     572    IMGUI_API void          PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
     573    IMGUI_API void          PlotHistogram(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0));
     574
     575    // Widgets: Value() Helpers.
     576    // - Those are merely shortcut to calling Text() with a format string. Output single value in "name: value" format (tip: freely declare more in your code to handle your types. you can add functions to the ImGui namespace)
     577    IMGUI_API void          Value(const char* prefix, bool b);
     578    IMGUI_API void          Value(const char* prefix, int v);
     579    IMGUI_API void          Value(const char* prefix, unsigned int v);
     580    IMGUI_API void          Value(const char* prefix, float v, const char* float_format = NULL);
     581
     582    // Widgets: Menus
     583    // - Use BeginMenuBar() on a window ImGuiWindowFlags_MenuBar to append to its menu bar.
     584    // - Use BeginMainMenuBar() to create a menu bar at the top of the screen and append to it.
     585    // - Use BeginMenu() to create a menu. You can call BeginMenu() multiple time with the same identifier to append more items to it.
     586    IMGUI_API bool          BeginMenuBar();                                                     // append to menu-bar of current window (requires ImGuiWindowFlags_MenuBar flag set on parent window).
     587    IMGUI_API void          EndMenuBar();                                                       // only call EndMenuBar() if BeginMenuBar() returns true!
     588    IMGUI_API bool          BeginMainMenuBar();                                                 // create and append to a full screen menu-bar.
     589    IMGUI_API void          EndMainMenuBar();                                                   // only call EndMainMenuBar() if BeginMainMenuBar() returns true!
     590    IMGUI_API bool          BeginMenu(const char* label, bool enabled = true);                  // create a sub-menu entry. only call EndMenu() if this returns true!
     591    IMGUI_API void          EndMenu();                                                          // only call EndMenu() if BeginMenu() returns true!
     592    IMGUI_API bool          MenuItem(const char* label, const char* shortcut = NULL, bool selected = false, bool enabled = true);  // return true when activated. shortcuts are displayed for convenience but not processed by ImGui at the moment
     593    IMGUI_API bool          MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true);              // return true when activated + toggle (*p_selected) if p_selected != NULL
     594
     595    // Tooltips
     596    // - Tooltip are windows following the mouse which do not take focus away.
     597    IMGUI_API void          BeginTooltip();                                                     // begin/append a tooltip window. to create full-featured tooltip (with any kind of items).
     598    IMGUI_API void          EndTooltip();
     599    IMGUI_API void          SetTooltip(const char* fmt, ...) IM_FMTARGS(1);                     // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip().
     600    IMGUI_API void          SetTooltipV(const char* fmt, va_list args) IM_FMTLIST(1);
     601
     602    // Popups, Modals
     603    //  - They block normal mouse hovering detection (and therefore most mouse interactions) behind them.
     604    //  - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
     605    //  - Their visibility state (~bool) is held internally instead of being held by the programmer as we are used to with regular Begin*() calls.
     606    //  - The 3 properties above are related: we need to retain popup visibility state in the library because popups may be closed as any time.
     607    //  - You can bypass the hovering restriction by using ImGuiHoveredFlags_AllowWhenBlockedByPopup when calling IsItemHovered() or IsWindowHovered().
     608    //  - IMPORTANT: Popup identifiers are relative to the current ID stack, so OpenPopup and BeginPopup generally needs to be at the same level of the stack.
     609    //    This is sometimes leading to confusing mistakes. May rework this in the future.
     610    // Popups: begin/end functions
     611    //  - BeginPopup(): query popup state, if open start appending into the window. Call EndPopup() afterwards. ImGuiWindowFlags are forwarded to the window.
     612    //  - BeginPopupModal(): block every interactions behind the window, cannot be closed by user, add a dimming background, has a title bar.
     613    IMGUI_API bool          BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0);                         // return true if the popup is open, and you can start outputting to it.
     614    IMGUI_API bool          BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // return true if the modal is open, and you can start outputting to it.
     615    IMGUI_API void          EndPopup();                                                                         // only call EndPopup() if BeginPopupXXX() returns true!
     616    // Popups: open/close functions
     617    //  - OpenPopup(): set popup state to open. ImGuiPopupFlags are available for opening options.
     618    //  - If not modal: they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
     619    //  - CloseCurrentPopup(): use inside the BeginPopup()/EndPopup() scope to close manually.
     620    //  - CloseCurrentPopup() is called by default by Selectable()/MenuItem() when activated (FIXME: need some options).
     621    //  - Use ImGuiPopupFlags_NoOpenOverExistingPopup to avoid opening a popup if there's already one at the same level. This is equivalent to e.g. testing for !IsAnyPopupOpen() prior to OpenPopup().
     622    IMGUI_API void          OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags = 0);                     // call to mark popup as open (don't call every frame!).
     623    IMGUI_API void          OpenPopupOnItemClick(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);   // helper to open popup when clicked on last item. return true when just opened. (note: actually triggers on the mouse _released_ event to be consistent with popup behaviors)
     624    IMGUI_API void          CloseCurrentPopup();                                                                // manually close the popup we have begin-ed into.
     625    // Popups: open+begin combined functions helpers
     626    //  - Helpers to do OpenPopup+BeginPopup where the Open action is triggered by e.g. hovering an item and right-clicking.
     627    //  - They are convenient to easily create context menus, hence the name.
     628    //  - IMPORTANT: Notice that BeginPopupContextXXX takes ImGuiPopupFlags just like OpenPopup() and unlike BeginPopup(). For full consistency, we may add ImGuiWindowFlags to the BeginPopupContextXXX functions in the future.
     629    //  - IMPORTANT: we exceptionally default their flags to 1 (== ImGuiPopupFlags_MouseButtonRight) for backward compatibility with older API taking 'int mouse_button = 1' parameter, so if you add other flags remember to re-add the ImGuiPopupFlags_MouseButtonRight.
     630    IMGUI_API bool          BeginPopupContextItem(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);  // open+begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp!
     631    IMGUI_API bool          BeginPopupContextWindow(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);// open+begin popup when clicked on current window.
     632    IMGUI_API bool          BeginPopupContextVoid(const char* str_id = NULL, ImGuiPopupFlags popup_flags = 1);  // open+begin popup when clicked in void (where there are no windows).
     633    // Popups: test function
     634    //  - IsPopupOpen(): return true if the popup is open at the current BeginPopup() level of the popup stack.
     635    //  - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId: return true if any popup is open at the current BeginPopup() level of the popup stack.
     636    //  - IsPopupOpen() with ImGuiPopupFlags_AnyPopupId + ImGuiPopupFlags_AnyPopupLevel: return true if any popup is open.
     637    IMGUI_API bool          IsPopupOpen(const char* str_id, ImGuiPopupFlags flags = 0);                         // return true if the popup is open.
     638
     639    // Columns
     640    // - You can also use SameLine(pos_x) to mimic simplified columns.
     641    // - The columns API is work-in-progress and rather lacking (columns are arguably the worst part of dear imgui at the moment!)
     642    // - There is a maximum of 64 columns.
     643    // - Currently working on new 'Tables' api which will replace columns around Q2 2020 (see GitHub #2957).
     644    IMGUI_API void          Columns(int count = 1, const char* id = NULL, bool border = true);
     645    IMGUI_API void          NextColumn();                                                       // next column, defaults to current row or next row if the current row is finished
     646    IMGUI_API int           GetColumnIndex();                                                   // get current column index
     647    IMGUI_API float         GetColumnWidth(int column_index = -1);                              // get column width (in pixels). pass -1 to use current column
     648    IMGUI_API void          SetColumnWidth(int column_index, float width);                      // set column width (in pixels). pass -1 to use current column
     649    IMGUI_API float         GetColumnOffset(int column_index = -1);                             // get position of column line (in pixels, from the left side of the contents region). pass -1 to use current column, otherwise 0..GetColumnsCount() inclusive. column 0 is typically 0.0f
     650    IMGUI_API void          SetColumnOffset(int column_index, float offset_x);                  // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column
     651    IMGUI_API int           GetColumnsCount();
     652
     653    // Tab Bars, Tabs
     654    IMGUI_API bool          BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0);        // create and append into a TabBar
     655    IMGUI_API void          EndTabBar();                                                        // only call EndTabBar() if BeginTabBar() returns true!
     656    IMGUI_API bool          BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags flags = 0); // create a Tab. Returns true if the Tab is selected.
     657    IMGUI_API void          EndTabItem();                                                       // only call EndTabItem() if BeginTabItem() returns true!
     658    IMGUI_API bool          TabItemButton(const char* label, ImGuiTabItemFlags flags = 0);      // create a Tab behaving like a button. return true when clicked. cannot be selected in the tab bar.
     659    IMGUI_API void          SetTabItemClosed(const char* tab_or_docked_window_label);           // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name.
     660
     661    // Logging/Capture
     662    // - All text output from the interface can be captured into tty/file/clipboard. By default, tree nodes are automatically opened during logging.
     663    IMGUI_API void          LogToTTY(int auto_open_depth = -1);                                 // start logging to tty (stdout)
     664    IMGUI_API void          LogToFile(int auto_open_depth = -1, const char* filename = NULL);   // start logging to file
     665    IMGUI_API void          LogToClipboard(int auto_open_depth = -1);                           // start logging to OS clipboard
     666    IMGUI_API void          LogFinish();                                                        // stop logging (close file, etc.)
     667    IMGUI_API void          LogButtons();                                                       // helper to display buttons for logging to tty/file/clipboard
     668    IMGUI_API void          LogText(const char* fmt, ...) IM_FMTARGS(1);                        // pass text data straight to log (without being displayed)
     669
     670    // Drag and Drop
     671    // - [BETA API] API may evolve!
     672    // - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip as replacement)
     673    IMGUI_API bool          BeginDragDropSource(ImGuiDragDropFlags flags = 0);                                      // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource()
     674    IMGUI_API bool          SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0);  // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui.
     675    IMGUI_API void          EndDragDropSource();                                                                    // only call EndDragDropSource() if BeginDragDropSource() returns true!
     676    IMGUI_API bool                  BeginDragDropTarget();                                                          // call after submitting an item that may receive a payload. If this returns true, you can call AcceptDragDropPayload() + EndDragDropTarget()
     677    IMGUI_API const ImGuiPayload*   AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags = 0);          // accept contents of a given type. If ImGuiDragDropFlags_AcceptBeforeDelivery is set you can peek into the payload before the mouse button is released.
     678    IMGUI_API void                  EndDragDropTarget();                                                            // only call EndDragDropTarget() if BeginDragDropTarget() returns true!
     679    IMGUI_API const ImGuiPayload*   GetDragDropPayload();                                                           // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type.
     680
     681    // Clipping
     682    IMGUI_API void          PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect);
     683    IMGUI_API void          PopClipRect();
     684
     685    // Focus, Activation
     686    // - Prefer using "SetItemDefaultFocus()" over "if (IsWindowAppearing()) SetScrollHereY()" when applicable to signify "this is the default item"
     687    IMGUI_API void          SetItemDefaultFocus();                                              // make last item the default focused item of a window.
     688    IMGUI_API void          SetKeyboardFocusHere(int offset = 0);                               // focus keyboard on the next widget. Use positive 'offset' to access sub components of a multiple component widget. Use -1 to access previous widget.
     689
     690    // Item/Widgets Utilities
     691    // - Most of the functions are referring to the last/previous item we submitted.
     692    // - See Demo Window under "Widgets->Querying Status" for an interactive visualization of most of those functions.
     693    IMGUI_API bool          IsItemHovered(ImGuiHoveredFlags flags = 0);                         // is the last item hovered? (and usable, aka not blocked by a popup, etc.). See ImGuiHoveredFlags for more options.
     694    IMGUI_API bool          IsItemActive();                                                     // is the last item active? (e.g. button being held, text field being edited. This will continuously return true while holding mouse button on an item. Items that don't interact will always return false)
     695    IMGUI_API bool          IsItemFocused();                                                    // is the last item focused for keyboard/gamepad navigation?
     696    IMGUI_API bool          IsItemClicked(ImGuiMouseButton mouse_button = 0);                   // is the last item clicked? (e.g. button/node just clicked on) == IsMouseClicked(mouse_button) && IsItemHovered()
     697    IMGUI_API bool          IsItemVisible();                                                    // is the last item visible? (items may be out of sight because of clipping/scrolling)
     698    IMGUI_API bool          IsItemEdited();                                                     // did the last item modify its underlying value this frame? or was pressed? This is generally the same as the "bool" return value of many widgets.
     699    IMGUI_API bool          IsItemActivated();                                                  // was the last item just made active (item was previously inactive).
     700    IMGUI_API bool          IsItemDeactivated();                                                // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing.
     701    IMGUI_API bool          IsItemDeactivatedAfterEdit();                                       // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item).
     702    IMGUI_API bool          IsItemToggledOpen();                                                // was the last item open state toggled? set by TreeNode().
     703    IMGUI_API bool          IsAnyItemHovered();                                                 // is any item hovered?
     704    IMGUI_API bool          IsAnyItemActive();                                                  // is any item active?
     705    IMGUI_API bool          IsAnyItemFocused();                                                 // is any item focused?
     706    IMGUI_API ImVec2        GetItemRectMin();                                                   // get upper-left bounding rectangle of the last item (screen space)
     707    IMGUI_API ImVec2        GetItemRectMax();                                                   // get lower-right bounding rectangle of the last item (screen space)
     708    IMGUI_API ImVec2        GetItemRectSize();                                                  // get size of last item
     709    IMGUI_API void          SetItemAllowOverlap();                                              // allow last item to be overlapped by a subsequent item. sometimes useful with invisible buttons, selectables, etc. to catch unused area.
     710
     711    // Miscellaneous Utilities
     712    IMGUI_API bool          IsRectVisible(const ImVec2& size);                                  // test if rectangle (of given size, starting from cursor position) is visible / not clipped.
     713    IMGUI_API bool          IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max);      // test if rectangle (in screen space) is visible / not clipped. to perform coarse clipping on user's side.
     714    IMGUI_API double        GetTime();                                                          // get global imgui time. incremented by io.DeltaTime every frame.
     715    IMGUI_API int           GetFrameCount();                                                    // get global imgui frame count. incremented by 1 every frame.
     716    IMGUI_API ImDrawList*   GetBackgroundDrawList();                                            // this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
     717    IMGUI_API ImDrawList*   GetForegroundDrawList();                                            // this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.
     718    IMGUI_API ImDrawListSharedData* GetDrawListSharedData();                                    // you may use this when creating your own ImDrawList instances.
     719    IMGUI_API const char*   GetStyleColorName(ImGuiCol idx);                                    // get a string corresponding to the enum value (for display, saving, etc.).
     720    IMGUI_API void          SetStateStorage(ImGuiStorage* storage);                             // replace current window storage with our own (if you want to manipulate it yourself, typically clear subsection of it)
     721    IMGUI_API ImGuiStorage* GetStateStorage();
     722    IMGUI_API void          CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end);    // calculate coarse clipping for large list of evenly sized items. Prefer using the ImGuiListClipper higher-level helper if you can.
     723    IMGUI_API bool          BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0); // helper to create a child window / scrolling region that looks like a normal widget frame
     724    IMGUI_API void          EndChildFrame();                                                    // always call EndChildFrame() regardless of BeginChildFrame() return values (which indicates a collapsed/clipped window)
     725
     726    // Text Utilities
     727    IMGUI_API ImVec2        CalcTextSize(const char* text, const char* text_end = NULL, bool hide_text_after_double_hash = false, float wrap_width = -1.0f);
     728
     729    // Color Utilities
     730    IMGUI_API ImVec4        ColorConvertU32ToFloat4(ImU32 in);
     731    IMGUI_API ImU32         ColorConvertFloat4ToU32(const ImVec4& in);
     732    IMGUI_API void          ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v);
     733    IMGUI_API void          ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b);
     734
     735    // Inputs Utilities: Keyboard
     736    // - For 'int user_key_index' you can use your own indices/enums according to how your back-end/engine stored them in io.KeysDown[].
     737    // - We don't know the meaning of those value. You can use GetKeyIndex() to map a ImGuiKey_ value into the user index.
     738    IMGUI_API int           GetKeyIndex(ImGuiKey imgui_key);                                    // map ImGuiKey_* values into user's key index. == io.KeyMap[key]
     739    IMGUI_API bool          IsKeyDown(int user_key_index);                                      // is key being held. == io.KeysDown[user_key_index].
     740    IMGUI_API bool          IsKeyPressed(int user_key_index, bool repeat = true);               // was key pressed (went from !Down to Down)? if repeat=true, uses io.KeyRepeatDelay / KeyRepeatRate
     741    IMGUI_API bool          IsKeyReleased(int user_key_index);                                  // was key released (went from Down to !Down)?
     742    IMGUI_API int           GetKeyPressedAmount(int key_index, float repeat_delay, float rate); // uses provided repeat rate/delay. return a count, most often 0 or 1 but might be >1 if RepeatRate is small enough that DeltaTime > RepeatRate
     743    IMGUI_API void          CaptureKeyboardFromApp(bool want_capture_keyboard_value = true);    // attention: misleading name! manually override io.WantCaptureKeyboard flag next frame (said flag is entirely left for your application to handle). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard_value"; after the next NewFrame() call.
     744
     745    // Inputs Utilities: Mouse
     746    // - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right.
     747    // - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle.
     748    // - Dragging operations are only reported after mouse has moved a certain distance away from the initial clicking position (see 'lock_threshold' and 'io.MouseDraggingThreshold')
     749    IMGUI_API bool          IsMouseDown(ImGuiMouseButton button);                               // is mouse button held?
     750    IMGUI_API bool          IsMouseClicked(ImGuiMouseButton button, bool repeat = false);       // did mouse button clicked? (went from !Down to Down)
     751    IMGUI_API bool          IsMouseReleased(ImGuiMouseButton button);                           // did mouse button released? (went from Down to !Down)
     752    IMGUI_API bool          IsMouseDoubleClicked(ImGuiMouseButton button);                      // did mouse button double-clicked? (note that a double-click will also report IsMouseClicked() == true)
     753    IMGUI_API bool          IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true);// is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block.
     754    IMGUI_API bool          IsMousePosValid(const ImVec2* mouse_pos = NULL);                    // by convention we use (-FLT_MAX,-FLT_MAX) to denote that there is no mouse available
     755    IMGUI_API bool          IsAnyMouseDown();                                                   // is any mouse button held?
     756    IMGUI_API ImVec2        GetMousePos();                                                      // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls
     757    IMGUI_API ImVec2        GetMousePosOnOpeningCurrentPopup();                                 // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves)
     758    IMGUI_API bool          IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f);         // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold)
     759    IMGUI_API ImVec2        GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f);   // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold)
     760    IMGUI_API void          ResetMouseDragDelta(ImGuiMouseButton button = 0);                   //
     761    IMGUI_API ImGuiMouseCursor GetMouseCursor();                                                // get desired cursor type, reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you
     762    IMGUI_API void          SetMouseCursor(ImGuiMouseCursor cursor_type);                       // set desired cursor type
     763    IMGUI_API void          CaptureMouseFromApp(bool want_capture_mouse_value = true);          // attention: misleading name! manually override io.WantCaptureMouse flag next frame (said flag is entirely left for your application to handle). This is equivalent to setting "io.WantCaptureMouse = want_capture_mouse_value;" after the next NewFrame() call.
     764
     765    // Clipboard Utilities
     766    // - Also see the LogToClipboard() function to capture GUI into clipboard, or easily output text data to the clipboard.
     767    IMGUI_API const char*   GetClipboardText();
     768    IMGUI_API void          SetClipboardText(const char* text);
     769
     770    // Settings/.Ini Utilities
     771    // - The disk functions are automatically called if io.IniFilename != NULL (default is "imgui.ini").
     772    // - Set io.IniFilename to NULL to load/save manually. Read io.WantSaveIniSettings description about handling .ini saving manually.
     773    IMGUI_API void          LoadIniSettingsFromDisk(const char* ini_filename);                  // call after CreateContext() and before the first call to NewFrame(). NewFrame() automatically calls LoadIniSettingsFromDisk(io.IniFilename).
     774    IMGUI_API void          LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size=0); // call after CreateContext() and before the first call to NewFrame() to provide .ini data from your own data source.
     775    IMGUI_API void          SaveIniSettingsToDisk(const char* ini_filename);                    // this is automatically called (if io.IniFilename is not empty) a few seconds after any modification that should be reflected in the .ini file (and also by DestroyContext).
     776    IMGUI_API const char*   SaveIniSettingsToMemory(size_t* out_ini_size = NULL);               // return a zero-terminated string with the .ini data which you can save by your own mean. call when io.WantSaveIniSettings is set, then save data by your own mean and clear io.WantSaveIniSettings.
     777
     778    // Debug Utilities
     779    IMGUI_API bool          DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro.
     780
     781    // Memory Allocators
     782    // - All those functions are not reliant on the current context.
     783    // - If you reload the contents of imgui.cpp at runtime, you may need to call SetCurrentContext() + SetAllocatorFunctions() again because we use global storage for those.
     784    IMGUI_API void          SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data = NULL);
     785    IMGUI_API void*         MemAlloc(size_t size);
     786    IMGUI_API void          MemFree(void* ptr);
    553787
    554788} // namespace ImGui
    555789
    556   // Flags for ImGui::Begin()
     790//-----------------------------------------------------------------------------
     791// Flags & Enumerations
     792//-----------------------------------------------------------------------------
     793
     794// Flags for ImGui::Begin()
    557795enum ImGuiWindowFlags_
    558796{
    559    ImGuiWindowFlags_NoTitleBar = 1 << 0,   // Disable title-bar
    560    ImGuiWindowFlags_NoResize = 1 << 1,   // Disable user resizing with the lower-right grip
    561    ImGuiWindowFlags_NoMove = 1 << 2,   // Disable user moving the window
    562    ImGuiWindowFlags_NoScrollbar = 1 << 3,   // Disable scrollbars (window can still scroll with mouse or programatically)
    563    ImGuiWindowFlags_NoScrollWithMouse = 1 << 4,   // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set.
    564    ImGuiWindowFlags_NoCollapse = 1 << 5,   // Disable user collapsing window by double-clicking on it
    565    ImGuiWindowFlags_AlwaysAutoResize = 1 << 6,   // Resize every window to its content every frame
    566    //ImGuiWindowFlags_ShowBorders          = 1 << 7,   // Show borders around windows and items (OBSOLETE! Use e.g. style.FrameBorderSize=1.0f to enable borders).
    567    ImGuiWindowFlags_NoSavedSettings = 1 << 8,   // Never load/save settings in .ini file
    568    ImGuiWindowFlags_NoInputs = 1 << 9,   // Disable catching mouse or keyboard inputs, hovering test with pass through.
    569    ImGuiWindowFlags_MenuBar = 1 << 10,  // Has a menu-bar
    570    ImGuiWindowFlags_HorizontalScrollbar = 1 << 11,  // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section.
    571    ImGuiWindowFlags_NoFocusOnAppearing = 1 << 12,  // Disable taking focus when transitioning from hidden to visible state
    572    ImGuiWindowFlags_NoBringToFrontOnFocus = 1 << 13,  // Disable bringing window to front when taking focus (e.g. clicking on it or programatically giving it focus)
    573    ImGuiWindowFlags_AlwaysVerticalScrollbar = 1 << 14,  // Always show vertical scrollbar (even if ContentSize.y < Size.y)
    574    ImGuiWindowFlags_AlwaysHorizontalScrollbar = 1 << 15,  // Always show horizontal scrollbar (even if ContentSize.x < Size.x)
    575    ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16,  // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient)
    576    ImGuiWindowFlags_ResizeFromAnySide = 1 << 17,  // [BETA] Enable resize from any corners and borders. Your back-end needs to honor the different values of io.MouseCursor set by imgui.
    577    ImGuiWindowFlags_NoNavInputs = 1 << 18,  // No gamepad/keyboard navigation within the window
    578    ImGuiWindowFlags_NoNavFocus = 1 << 19,  // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)
    579    ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
    580 
    581    // [Internal]
    582    ImGuiWindowFlags_NavFlattened = 1 << 23,  // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
    583    ImGuiWindowFlags_ChildWindow = 1 << 24,  // Don't use! For internal use by BeginChild()
    584    ImGuiWindowFlags_Tooltip = 1 << 25,  // Don't use! For internal use by BeginTooltip()
    585    ImGuiWindowFlags_Popup = 1 << 26,  // Don't use! For internal use by BeginPopup()
    586    ImGuiWindowFlags_Modal = 1 << 27,  // Don't use! For internal use by BeginPopupModal()
    587    ImGuiWindowFlags_ChildMenu = 1 << 28   // Don't use! For internal use by BeginMenu()
     797    ImGuiWindowFlags_None                   = 0,
     798    ImGuiWindowFlags_NoTitleBar             = 1 << 0,   // Disable title-bar
     799    ImGuiWindowFlags_NoResize               = 1 << 1,   // Disable user resizing with the lower-right grip
     800    ImGuiWindowFlags_NoMove                 = 1 << 2,   // Disable user moving the window
     801    ImGuiWindowFlags_NoScrollbar            = 1 << 3,   // Disable scrollbars (window can still scroll with mouse or programmatically)
     802    ImGuiWindowFlags_NoScrollWithMouse      = 1 << 4,   // Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set.
     803    ImGuiWindowFlags_NoCollapse             = 1 << 5,   // Disable user collapsing window by double-clicking on it
     804    ImGuiWindowFlags_AlwaysAutoResize       = 1 << 6,   // Resize every window to its content every frame
     805    ImGuiWindowFlags_NoBackground           = 1 << 7,   // Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f).
     806    ImGuiWindowFlags_NoSavedSettings        = 1 << 8,   // Never load/save settings in .ini file
     807    ImGuiWindowFlags_NoMouseInputs          = 1 << 9,   // Disable catching mouse, hovering test with pass through.
     808    ImGuiWindowFlags_MenuBar                = 1 << 10,  // Has a menu-bar
     809    ImGuiWindowFlags_HorizontalScrollbar    = 1 << 11,  // Allow horizontal scrollbar to appear (off by default). You may use SetNextWindowContentSize(ImVec2(width,0.0f)); prior to calling Begin() to specify width. Read code in imgui_demo in the "Horizontal Scrolling" section.
     810    ImGuiWindowFlags_NoFocusOnAppearing     = 1 << 12,  // Disable taking focus when transitioning from hidden to visible state
     811    ImGuiWindowFlags_NoBringToFrontOnFocus  = 1 << 13,  // Disable bringing window to front when taking focus (e.g. clicking on it or programmatically giving it focus)
     812    ImGuiWindowFlags_AlwaysVerticalScrollbar= 1 << 14,  // Always show vertical scrollbar (even if ContentSize.y < Size.y)
     813    ImGuiWindowFlags_AlwaysHorizontalScrollbar=1<< 15,  // Always show horizontal scrollbar (even if ContentSize.x < Size.x)
     814    ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 16,  // Ensure child windows without border uses style.WindowPadding (ignored by default for non-bordered child windows, because more convenient)
     815    ImGuiWindowFlags_NoNavInputs            = 1 << 18,  // No gamepad/keyboard navigation within the window
     816    ImGuiWindowFlags_NoNavFocus             = 1 << 19,  // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)
     817    ImGuiWindowFlags_UnsavedDocument        = 1 << 20,  // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker.
     818    ImGuiWindowFlags_NoNav                  = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
     819    ImGuiWindowFlags_NoDecoration           = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse,
     820    ImGuiWindowFlags_NoInputs               = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
     821
     822    // [Internal]
     823    ImGuiWindowFlags_NavFlattened           = 1 << 23,  // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
     824    ImGuiWindowFlags_ChildWindow            = 1 << 24,  // Don't use! For internal use by BeginChild()
     825    ImGuiWindowFlags_Tooltip                = 1 << 25,  // Don't use! For internal use by BeginTooltip()
     826    ImGuiWindowFlags_Popup                  = 1 << 26,  // Don't use! For internal use by BeginPopup()
     827    ImGuiWindowFlags_Modal                  = 1 << 27,  // Don't use! For internal use by BeginPopupModal()
     828    ImGuiWindowFlags_ChildMenu              = 1 << 28   // Don't use! For internal use by BeginMenu()
     829
     830    // [Obsolete]
     831    //ImGuiWindowFlags_ShowBorders          = 1 << 7,   // --> Set style.FrameBorderSize=1.0f or style.WindowBorderSize=1.0f to enable borders around items or windows.
     832    //ImGuiWindowFlags_ResizeFromAnySide    = 1 << 17,  // --> Set io.ConfigWindowsResizeFromEdges=true and make sure mouse cursors are supported by back-end (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors)
    588833};
    589834
     
    591836enum ImGuiInputTextFlags_
    592837{
    593    ImGuiInputTextFlags_CharsDecimal = 1 << 0,   // Allow 0123456789.+-*/
    594    ImGuiInputTextFlags_CharsHexadecimal = 1 << 1,   // Allow 0123456789ABCDEFabcdef
    595    ImGuiInputTextFlags_CharsUppercase = 1 << 2,   // Turn a..z into A..Z
    596    ImGuiInputTextFlags_CharsNoBlank = 1 << 3,   // Filter out spaces, tabs
    597    ImGuiInputTextFlags_AutoSelectAll = 1 << 4,   // Select entire text when first taking mouse focus
    598    ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5,   // Return 'true' when Enter is pressed (as opposed to when the value was modified)
    599    ImGuiInputTextFlags_CallbackCompletion = 1 << 6,   // Call user function on pressing TAB (for completion handling)
    600    ImGuiInputTextFlags_CallbackHistory = 1 << 7,   // Call user function on pressing Up/Down arrows (for history handling)
    601    ImGuiInputTextFlags_CallbackAlways = 1 << 8,   // Call user function every time. User code may query cursor position, modify text buffer.
    602    ImGuiInputTextFlags_CallbackCharFilter = 1 << 9,   // Call user function to filter character. Modify data->EventChar to replace/filter input, or return 1 to discard character.
    603    ImGuiInputTextFlags_AllowTabInput = 1 << 10,  // Pressing TAB input a '\t' character into the text field
    604    ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11,  // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter).
    605    ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12,  // Disable following the cursor horizontally
    606    ImGuiInputTextFlags_AlwaysInsertMode = 1 << 13,  // Insert mode
    607    ImGuiInputTextFlags_ReadOnly = 1 << 14,  // Read-only mode
    608    ImGuiInputTextFlags_Password = 1 << 15,  // Password mode, display all characters as '*'
    609    ImGuiInputTextFlags_NoUndoRedo = 1 << 16,  // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
    610    ImGuiInputTextFlags_CharsScientific = 1 << 17,  // Allow 0123456789.+-*/eE (Scientific notation input)
    611                                                    // [Internal]
    612                                                    ImGuiInputTextFlags_Multiline = 1 << 20   // For internal use by InputTextMultiline()
     838    ImGuiInputTextFlags_None                = 0,
     839    ImGuiInputTextFlags_CharsDecimal        = 1 << 0,   // Allow 0123456789.+-*/
     840    ImGuiInputTextFlags_CharsHexadecimal    = 1 << 1,   // Allow 0123456789ABCDEFabcdef
     841    ImGuiInputTextFlags_CharsUppercase      = 1 << 2,   // Turn a..z into A..Z
     842    ImGuiInputTextFlags_CharsNoBlank        = 1 << 3,   // Filter out spaces, tabs
     843    ImGuiInputTextFlags_AutoSelectAll       = 1 << 4,   // Select entire text when first taking mouse focus
     844    ImGuiInputTextFlags_EnterReturnsTrue    = 1 << 5,   // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function.
     845    ImGuiInputTextFlags_CallbackCompletion  = 1 << 6,   // Callback on pressing TAB (for completion handling)
     846    ImGuiInputTextFlags_CallbackHistory     = 1 << 7,   // Callback on pressing Up/Down arrows (for history handling)
     847    ImGuiInputTextFlags_CallbackAlways      = 1 << 8,   // Callback on each iteration. User code may query cursor position, modify text buffer.
     848    ImGuiInputTextFlags_CallbackCharFilter  = 1 << 9,   // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
     849    ImGuiInputTextFlags_AllowTabInput       = 1 << 10,  // Pressing TAB input a '\t' character into the text field
     850    ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11,  // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter).
     851    ImGuiInputTextFlags_NoHorizontalScroll  = 1 << 12,  // Disable following the cursor horizontally
     852    ImGuiInputTextFlags_AlwaysInsertMode    = 1 << 13,  // Insert mode
     853    ImGuiInputTextFlags_ReadOnly            = 1 << 14,  // Read-only mode
     854    ImGuiInputTextFlags_Password            = 1 << 15,  // Password mode, display all characters as '*'
     855    ImGuiInputTextFlags_NoUndoRedo          = 1 << 16,  // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
     856    ImGuiInputTextFlags_CharsScientific     = 1 << 17,  // Allow 0123456789.+-*/eE (Scientific notation input)
     857    ImGuiInputTextFlags_CallbackResize      = 1 << 18,  // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)
     858    ImGuiInputTextFlags_CallbackEdit        = 1 << 19,  // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
     859    // [Internal]
     860    ImGuiInputTextFlags_Multiline           = 1 << 20,  // For internal use by InputTextMultiline()
     861    ImGuiInputTextFlags_NoMarkEdited        = 1 << 21   // For internal use by functions using InputText() before reformatting data
    613862};
    614863
     
    616865enum ImGuiTreeNodeFlags_
    617866{
    618    ImGuiTreeNodeFlags_Selected = 1 << 0,   // Draw as selected
    619    ImGuiTreeNodeFlags_Framed = 1 << 1,   // Full colored frame (e.g. for CollapsingHeader)
    620    ImGuiTreeNodeFlags_AllowItemOverlap = 1 << 2,   // Hit testing to allow subsequent widgets to overlap this one
    621    ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3,   // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack
    622    ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4,   // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes)
    623    ImGuiTreeNodeFlags_DefaultOpen = 1 << 5,   // Default node to be open
    624    ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6,   // Need double-click to open node
    625    ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7,   // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open.
    626    ImGuiTreeNodeFlags_Leaf = 1 << 8,   // No collapsing, no arrow (use as a convenience for leaf nodes).
    627    ImGuiTreeNodeFlags_Bullet = 1 << 9,   // Display a bullet instead of arrow
    628    ImGuiTreeNodeFlags_FramePadding = 1 << 10,  // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().
    629                                                //ImGuITreeNodeFlags_SpanAllAvailWidth  = 1 << 11,  // FIXME: TODO: Extend hit box horizontally even if not framed
    630                                                //ImGuiTreeNodeFlags_NoScrollOnOpen     = 1 << 12,  // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible
    631                                                ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13,  // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
    632                                                ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoAutoOpenOnLog
    633 
    634                                                // Obsolete names (will be removed)
    635 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    636    , ImGuiTreeNodeFlags_AllowOverlapMode = ImGuiTreeNodeFlags_AllowItemOverlap
    637 #endif
     867    ImGuiTreeNodeFlags_None                 = 0,
     868    ImGuiTreeNodeFlags_Selected             = 1 << 0,   // Draw as selected
     869    ImGuiTreeNodeFlags_Framed               = 1 << 1,   // Full colored frame (e.g. for CollapsingHeader)
     870    ImGuiTreeNodeFlags_AllowItemOverlap     = 1 << 2,   // Hit testing to allow subsequent widgets to overlap this one
     871    ImGuiTreeNodeFlags_NoTreePushOnOpen     = 1 << 3,   // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack
     872    ImGuiTreeNodeFlags_NoAutoOpenOnLog      = 1 << 4,   // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes)
     873    ImGuiTreeNodeFlags_DefaultOpen          = 1 << 5,   // Default node to be open
     874    ImGuiTreeNodeFlags_OpenOnDoubleClick    = 1 << 6,   // Need double-click to open node
     875    ImGuiTreeNodeFlags_OpenOnArrow          = 1 << 7,   // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open.
     876    ImGuiTreeNodeFlags_Leaf                 = 1 << 8,   // No collapsing, no arrow (use as a convenience for leaf nodes).
     877    ImGuiTreeNodeFlags_Bullet               = 1 << 9,   // Display a bullet instead of arrow
     878    ImGuiTreeNodeFlags_FramePadding         = 1 << 10,  // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().
     879    ImGuiTreeNodeFlags_SpanAvailWidth       = 1 << 11,  // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default.
     880    ImGuiTreeNodeFlags_SpanFullWidth        = 1 << 12,  // Extend hit box to the left-most and right-most edges (bypass the indented area).
     881    ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13,  // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
     882    //ImGuiTreeNodeFlags_NoScrollOnOpen     = 1 << 14,  // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible
     883    ImGuiTreeNodeFlags_CollapsingHeader     = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog
     884};
     885
     886// Flags for OpenPopup*(), BeginPopupContext*(), IsPopupOpen() functions.
     887// - To be backward compatible with older API which took an 'int mouse_button = 1' argument, we need to treat
     888//   small flags values as a mouse button index, so we encode the mouse button in the first few bits of the flags.
     889//   It is therefore guaranteed to be legal to pass a mouse button index in ImGuiPopupFlags.
     890// - For the same reason, we exceptionally default the ImGuiPopupFlags argument of BeginPopupContextXXX functions to 1 instead of 0.
     891//   IMPORTANT: because the default parameter is 1 (==ImGuiPopupFlags_MouseButtonRight), if you rely on the default parameter
     892//   and want to another another flag, you need to pass in the ImGuiPopupFlags_MouseButtonRight flag.
     893// - Multiple buttons currently cannot be combined/or-ed in those functions (we could allow it later).
     894enum ImGuiPopupFlags_
     895{
     896    ImGuiPopupFlags_None                    = 0,
     897    ImGuiPopupFlags_MouseButtonLeft         = 0,        // For BeginPopupContext*(): open on Left Mouse release. Guaranteed to always be == 0 (same as ImGuiMouseButton_Left)
     898    ImGuiPopupFlags_MouseButtonRight        = 1,        // For BeginPopupContext*(): open on Right Mouse release. Guaranteed to always be == 1 (same as ImGuiMouseButton_Right)
     899    ImGuiPopupFlags_MouseButtonMiddle       = 2,        // For BeginPopupContext*(): open on Middle Mouse release. Guaranteed to always be == 2 (same as ImGuiMouseButton_Middle)
     900    ImGuiPopupFlags_MouseButtonMask_        = 0x1F,
     901    ImGuiPopupFlags_MouseButtonDefault_     = 1,
     902    ImGuiPopupFlags_NoOpenOverExistingPopup = 1 << 5,   // For OpenPopup*(), BeginPopupContext*(): don't open if there's already a popup at the same level of the popup stack
     903    ImGuiPopupFlags_NoOpenOverItems         = 1 << 6,   // For BeginPopupContextWindow(): don't return true when hovering items, only when hovering empty space
     904    ImGuiPopupFlags_AnyPopupId              = 1 << 7,   // For IsPopupOpen(): ignore the ImGuiID parameter and test for any popup.
     905    ImGuiPopupFlags_AnyPopupLevel           = 1 << 8,   // For IsPopupOpen(): search/test at any level of the popup stack (default test in the current level)
     906    ImGuiPopupFlags_AnyPopup                = ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel
    638907};
    639908
     
    641910enum ImGuiSelectableFlags_
    642911{
    643    ImGuiSelectableFlags_DontClosePopups = 1 << 0,   // Clicking this don't close parent popup window
    644    ImGuiSelectableFlags_SpanAllColumns = 1 << 1,   // Selectable frame can span all columns (text will still fit in current column)
    645    ImGuiSelectableFlags_AllowDoubleClick = 1 << 2    // Generate press events on double clicks too
     912    ImGuiSelectableFlags_None               = 0,
     913    ImGuiSelectableFlags_DontClosePopups    = 1 << 0,   // Clicking this don't close parent popup window
     914    ImGuiSelectableFlags_SpanAllColumns     = 1 << 1,   // Selectable frame can span all columns (text will still fit in current column)
     915    ImGuiSelectableFlags_AllowDoubleClick   = 1 << 2,   // Generate press events on double clicks too
     916    ImGuiSelectableFlags_Disabled           = 1 << 3,   // Cannot be selected, display grayed out text
     917    ImGuiSelectableFlags_AllowItemOverlap   = 1 << 4    // (WIP) Hit testing to allow subsequent widgets to overlap this one
    646918};
    647919
     
    649921enum ImGuiComboFlags_
    650922{
    651    ImGuiComboFlags_PopupAlignLeft = 1 << 0,   // Align the popup toward the left by default
    652    ImGuiComboFlags_HeightSmall = 1 << 1,   // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo()
    653    ImGuiComboFlags_HeightRegular = 1 << 2,   // Max ~8 items visible (default)
    654    ImGuiComboFlags_HeightLarge = 1 << 3,   // Max ~20 items visible
    655    ImGuiComboFlags_HeightLargest = 1 << 4,   // As many fitting items as possible
    656    ImGuiComboFlags_NoArrowButton = 1 << 5,   // Display on the preview box without the square arrow button
    657    ImGuiComboFlags_NoPreview = 1 << 6,   // Display only a square arrow button
    658    ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest
     923    ImGuiComboFlags_None                    = 0,
     924    ImGuiComboFlags_PopupAlignLeft          = 1 << 0,   // Align the popup toward the left by default
     925    ImGuiComboFlags_HeightSmall             = 1 << 1,   // Max ~4 items visible. Tip: If you want your combo popup to be a specific size you can use SetNextWindowSizeConstraints() prior to calling BeginCombo()
     926    ImGuiComboFlags_HeightRegular           = 1 << 2,   // Max ~8 items visible (default)
     927    ImGuiComboFlags_HeightLarge             = 1 << 3,   // Max ~20 items visible
     928    ImGuiComboFlags_HeightLargest           = 1 << 4,   // As many fitting items as possible
     929    ImGuiComboFlags_NoArrowButton           = 1 << 5,   // Display on the preview box without the square arrow button
     930    ImGuiComboFlags_NoPreview               = 1 << 6,   // Display only a square arrow button
     931    ImGuiComboFlags_HeightMask_             = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest
     932};
     933
     934// Flags for ImGui::BeginTabBar()
     935enum ImGuiTabBarFlags_
     936{
     937    ImGuiTabBarFlags_None                           = 0,
     938    ImGuiTabBarFlags_Reorderable                    = 1 << 0,   // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list
     939    ImGuiTabBarFlags_AutoSelectNewTabs              = 1 << 1,   // Automatically select new tabs when they appear
     940    ImGuiTabBarFlags_TabListPopupButton             = 1 << 2,   // Disable buttons to open the tab list popup
     941    ImGuiTabBarFlags_NoCloseWithMiddleMouseButton   = 1 << 3,   // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
     942    ImGuiTabBarFlags_NoTabListScrollingButtons      = 1 << 4,   // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll)
     943    ImGuiTabBarFlags_NoTooltip                      = 1 << 5,   // Disable tooltips when hovering a tab
     944    ImGuiTabBarFlags_FittingPolicyResizeDown        = 1 << 6,   // Resize tabs when they don't fit
     945    ImGuiTabBarFlags_FittingPolicyScroll            = 1 << 7,   // Add scroll buttons when tabs don't fit
     946    ImGuiTabBarFlags_FittingPolicyMask_             = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,
     947    ImGuiTabBarFlags_FittingPolicyDefault_          = ImGuiTabBarFlags_FittingPolicyResizeDown
     948};
     949
     950// Flags for ImGui::BeginTabItem()
     951enum ImGuiTabItemFlags_
     952{
     953    ImGuiTabItemFlags_None                          = 0,
     954    ImGuiTabItemFlags_UnsavedDocument               = 1 << 0,   // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker.
     955    ImGuiTabItemFlags_SetSelected                   = 1 << 1,   // Trigger flag to programmatically make the tab selected when calling BeginTabItem()
     956    ImGuiTabItemFlags_NoCloseWithMiddleMouseButton  = 1 << 2,   // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
     957    ImGuiTabItemFlags_NoPushId                      = 1 << 3,   // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem()
     958    ImGuiTabItemFlags_NoTooltip                     = 1 << 4,   // Disable tooltip for the given tab
     959    ImGuiTabItemFlags_NoReorder                     = 1 << 5,   // Disable reordering this tab or having another tab cross over this tab
     960    ImGuiTabItemFlags_Leading                       = 1 << 6,   // Enforce the tab position to the left of the tab bar (after the tab list popup button)
     961    ImGuiTabItemFlags_Trailing                      = 1 << 7    // Enforce the tab position to the right of the tab bar (before the scrolling buttons)
    659962};
    660963
     
    662965enum ImGuiFocusedFlags_
    663966{
    664    ImGuiFocusedFlags_ChildWindows = 1 << 0,   // IsWindowFocused(): Return true if any children of the window is focused
    665    ImGuiFocusedFlags_RootWindow = 1 << 1,   // IsWindowFocused(): Test from root window (top most parent of the current hierarchy)
    666    ImGuiFocusedFlags_AnyWindow = 1 << 2,   // IsWindowFocused(): Return true if any window is focused
    667    ImGuiFocusedFlags_RootAndChildWindows = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows
     967    ImGuiFocusedFlags_None                          = 0,
     968    ImGuiFocusedFlags_ChildWindows                  = 1 << 0,   // IsWindowFocused(): Return true if any children of the window is focused
     969    ImGuiFocusedFlags_RootWindow                    = 1 << 1,   // IsWindowFocused(): Test from root window (top most parent of the current hierarchy)
     970    ImGuiFocusedFlags_AnyWindow                     = 1 << 2,   // IsWindowFocused(): Return true if any window is focused. Important: If you are trying to tell how to dispatch your low-level inputs, do NOT use this. Use 'io.WantCaptureMouse' instead! Please read the FAQ!
     971    ImGuiFocusedFlags_RootAndChildWindows           = ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows
    668972};
    669973
    670974// Flags for ImGui::IsItemHovered(), ImGui::IsWindowHovered()
    671 // Note: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that. Please read the FAQ!
     975// Note: if you are trying to check whether your mouse should be dispatched to Dear ImGui or to your app, you should use 'io.WantCaptureMouse' instead! Please read the FAQ!
     976// Note: windows with the ImGuiWindowFlags_NoInputs flag are ignored by IsWindowHovered() calls.
    672977enum ImGuiHoveredFlags_
    673978{
    674    ImGuiHoveredFlags_Default = 0,        // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them.
    675    ImGuiHoveredFlags_ChildWindows = 1 << 0,   // IsWindowHovered() only: Return true if any children of the window is hovered
    676    ImGuiHoveredFlags_RootWindow = 1 << 1,   // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy)
    677    ImGuiHoveredFlags_AnyWindow = 1 << 2,   // IsWindowHovered() only: Return true if any window is hovered
    678    ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3,   // Return true even if a popup window is normally blocking access to this item/window
    679                                                          //ImGuiHoveredFlags_AllowWhenBlockedByModal     = 1 << 4,   // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet.
    680                                                          ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5,   // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns.
    681                                                          ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6,   // Return true even if the position is overlapped by another window
    682                                                          ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped,
    683                                                          ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows
     979    ImGuiHoveredFlags_None                          = 0,        // Return true if directly over the item/window, not obstructed by another window, not obstructed by an active popup or modal blocking inputs under them.
     980    ImGuiHoveredFlags_ChildWindows                  = 1 << 0,   // IsWindowHovered() only: Return true if any children of the window is hovered
     981    ImGuiHoveredFlags_RootWindow                    = 1 << 1,   // IsWindowHovered() only: Test from root window (top most parent of the current hierarchy)
     982    ImGuiHoveredFlags_AnyWindow                     = 1 << 2,   // IsWindowHovered() only: Return true if any window is hovered
     983    ImGuiHoveredFlags_AllowWhenBlockedByPopup       = 1 << 3,   // Return true even if a popup window is normally blocking access to this item/window
     984    //ImGuiHoveredFlags_AllowWhenBlockedByModal     = 1 << 4,   // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet.
     985    ImGuiHoveredFlags_AllowWhenBlockedByActiveItem  = 1 << 5,   // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns.
     986    ImGuiHoveredFlags_AllowWhenOverlapped           = 1 << 6,   // Return true even if the position is obstructed or overlapped by another window
     987    ImGuiHoveredFlags_AllowWhenDisabled             = 1 << 7,   // Return true even if the item is disabled
     988    ImGuiHoveredFlags_RectOnly                      = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped,
     989    ImGuiHoveredFlags_RootAndChildWindows           = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows
    684990};
    685991
     
    687993enum ImGuiDragDropFlags_
    688994{
    689    // BeginDragDropSource() flags
    690    ImGuiDragDropFlags_SourceNoPreviewTooltip = 1 << 0,   // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior.
    691    ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1,   // By default, when dragging we clear data so that IsItemHovered() will return true, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item.
    692    ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2,   // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item.
    693    ImGuiDragDropFlags_SourceAllowNullID = 1 << 3,   // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit.
    694    ImGuiDragDropFlags_SourceExtern = 1 << 4,   // External source (from outside of imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously.
    695                                                // AcceptDragDropPayload() flags
    696                                                ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10,  // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered.
    697                                                ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11,  // Do not draw the default highlight rectangle when hovering over target.
    698                                                ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect  // For peeking ahead and inspecting the payload before delivery.
     995    ImGuiDragDropFlags_None                         = 0,
     996    // BeginDragDropSource() flags
     997    ImGuiDragDropFlags_SourceNoPreviewTooltip       = 1 << 0,   // By default, a successful call to BeginDragDropSource opens a tooltip so you can display a preview or description of the source contents. This flag disable this behavior.
     998    ImGuiDragDropFlags_SourceNoDisableHover         = 1 << 1,   // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item.
     999    ImGuiDragDropFlags_SourceNoHoldToOpenOthers     = 1 << 2,   // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item.
     1000    ImGuiDragDropFlags_SourceAllowNullID            = 1 << 3,   // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit.
     1001    ImGuiDragDropFlags_SourceExtern                 = 1 << 4,   // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously.
     1002    ImGuiDragDropFlags_SourceAutoExpirePayload      = 1 << 5,   // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged)
     1003    // AcceptDragDropPayload() flags
     1004    ImGuiDragDropFlags_AcceptBeforeDelivery         = 1 << 10,  // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered.
     1005    ImGuiDragDropFlags_AcceptNoDrawDefaultRect      = 1 << 11,  // Do not draw the default highlight rectangle when hovering over target.
     1006    ImGuiDragDropFlags_AcceptNoPreviewTooltip       = 1 << 12,  // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site.
     1007    ImGuiDragDropFlags_AcceptPeekOnly               = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect  // For peeking ahead and inspecting the payload before delivery.
    6991008};
    7001009
    7011010// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui.
    702 #define IMGUI_PAYLOAD_TYPE_COLOR_3F     "_COL3F"    // float[3]: Standard type for colors, without alpha. User code may use this type. 
     1011#define IMGUI_PAYLOAD_TYPE_COLOR_3F     "_COL3F"    // float[3]: Standard type for colors, without alpha. User code may use this type.
    7031012#define IMGUI_PAYLOAD_TYPE_COLOR_4F     "_COL4F"    // float[4]: Standard type for colors. User code may use this type.
     1013
     1014// A primary data type
     1015enum ImGuiDataType_
     1016{
     1017    ImGuiDataType_S8,       // signed char / char (with sensible compilers)
     1018    ImGuiDataType_U8,       // unsigned char
     1019    ImGuiDataType_S16,      // short
     1020    ImGuiDataType_U16,      // unsigned short
     1021    ImGuiDataType_S32,      // int
     1022    ImGuiDataType_U32,      // unsigned int
     1023    ImGuiDataType_S64,      // long long / __int64
     1024    ImGuiDataType_U64,      // unsigned long long / unsigned __int64
     1025    ImGuiDataType_Float,    // float
     1026    ImGuiDataType_Double,   // double
     1027    ImGuiDataType_COUNT
     1028};
    7041029
    7051030// A cardinal direction
    7061031enum ImGuiDir_
    7071032{
    708    ImGuiDir_None = -1,
    709    ImGuiDir_Left = 0,
    710    ImGuiDir_Right = 1,
    711    ImGuiDir_Up = 2,
    712    ImGuiDir_Down = 3,
    713    ImGuiDir_COUNT
     1033    ImGuiDir_None    = -1,
     1034    ImGuiDir_Left    = 0,
     1035    ImGuiDir_Right  = 1,
     1036    ImGuiDir_Up      = 2,
     1037    ImGuiDir_Down    = 3,
     1038    ImGuiDir_COUNT
    7141039};
    7151040
     
    7171042enum ImGuiKey_
    7181043{
    719    ImGuiKey_Tab,
    720    ImGuiKey_LeftArrow,
    721    ImGuiKey_RightArrow,
    722    ImGuiKey_UpArrow,
    723    ImGuiKey_DownArrow,
    724    ImGuiKey_PageUp,
    725    ImGuiKey_PageDown,
    726    ImGuiKey_Home,
    727    ImGuiKey_End,
    728    ImGuiKey_Insert,
    729    ImGuiKey_Delete,
    730    ImGuiKey_Backspace,
    731    ImGuiKey_Space,
    732    ImGuiKey_Enter,
    733    ImGuiKey_Escape,
    734    ImGuiKey_A,         // for text edit CTRL+A: select all
    735    ImGuiKey_C,         // for text edit CTRL+C: copy
    736    ImGuiKey_V,         // for text edit CTRL+V: paste
    737    ImGuiKey_X,         // for text edit CTRL+X: cut
    738    ImGuiKey_Y,         // for text edit CTRL+Y: redo
    739    ImGuiKey_Z,         // for text edit CTRL+Z: undo
    740    ImGuiKey_COUNT
    741 };
    742 
    743 // [BETA] Gamepad/Keyboard directional navigation
     1044    ImGuiKey_Tab,
     1045    ImGuiKey_LeftArrow,
     1046    ImGuiKey_RightArrow,
     1047    ImGuiKey_UpArrow,
     1048    ImGuiKey_DownArrow,
     1049    ImGuiKey_PageUp,
     1050    ImGuiKey_PageDown,
     1051    ImGuiKey_Home,
     1052    ImGuiKey_End,
     1053    ImGuiKey_Insert,
     1054    ImGuiKey_Delete,
     1055    ImGuiKey_Backspace,
     1056    ImGuiKey_Space,
     1057    ImGuiKey_Enter,
     1058    ImGuiKey_Escape,
     1059    ImGuiKey_KeyPadEnter,
     1060    ImGuiKey_A,                 // for text edit CTRL+A: select all
     1061    ImGuiKey_C,                 // for text edit CTRL+C: copy
     1062    ImGuiKey_V,                 // for text edit CTRL+V: paste
     1063    ImGuiKey_X,                 // for text edit CTRL+X: cut
     1064    ImGuiKey_Y,                 // for text edit CTRL+Y: redo
     1065    ImGuiKey_Z,                 // for text edit CTRL+Z: undo
     1066    ImGuiKey_COUNT
     1067};
     1068
     1069// To test io.KeyMods (which is a combination of individual fields io.KeyCtrl, io.KeyShift, io.KeyAlt set by user/back-end)
     1070enum ImGuiKeyModFlags_
     1071{
     1072    ImGuiKeyModFlags_None       = 0,
     1073    ImGuiKeyModFlags_Ctrl       = 1 << 0,
     1074    ImGuiKeyModFlags_Shift      = 1 << 1,
     1075    ImGuiKeyModFlags_Alt        = 1 << 2,
     1076    ImGuiKeyModFlags_Super      = 1 << 3
     1077};
     1078
     1079// Gamepad/Keyboard navigation
    7441080// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
    7451081// Gamepad:  Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Back-end: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame().
    746 // Read instructions in imgui.cpp for more details. Download PNG/PSD at goo.gl/9LgVZW.
     1082// Read instructions in imgui.cpp for more details. Download PNG/PSD at http://goo.gl/9LgVZW.
    7471083enum ImGuiNavInput_
    7481084{
    749    // Gamepad Mapping
    750    ImGuiNavInput_Activate,      // activate / open / toggle / tweak value       // e.g. Cross  (PS4), A (Xbox), A (Switch), Space (Keyboard)
    751    ImGuiNavInput_Cancel,        // cancel / close / exit                        // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard)
    752    ImGuiNavInput_Input,         // text input / on-screen keyboard              // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard)
    753    ImGuiNavInput_Menu,          // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard)
    754    ImGuiNavInput_DpadLeft,      // move / tweak / resize window (w/ PadMenu)    // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard)
    755    ImGuiNavInput_DpadRight,     //
    756    ImGuiNavInput_DpadUp,        //
    757    ImGuiNavInput_DpadDown,      //
    758    ImGuiNavInput_LStickLeft,    // scroll / move window (w/ PadMenu)            // e.g. Left Analog Stick Left/Right/Up/Down
    759    ImGuiNavInput_LStickRight,   //
    760    ImGuiNavInput_LStickUp,      //
    761    ImGuiNavInput_LStickDown,    //
    762    ImGuiNavInput_FocusPrev,     // next window (w/ PadMenu)                     // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
    763    ImGuiNavInput_FocusNext,     // prev window (w/ PadMenu)                     // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)
    764    ImGuiNavInput_TweakSlow,     // slower tweaks                                // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
    765    ImGuiNavInput_TweakFast,     // faster tweaks                                // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)
    766 
    767                                 // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them.
    768                                 // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[].
    769                                 ImGuiNavInput_KeyMenu_,      // toggle menu                                  // = io.KeyAlt
    770                                 ImGuiNavInput_KeyLeft_,      // move left                                    // = Arrow keys
    771                                 ImGuiNavInput_KeyRight_,     // move right
    772                                 ImGuiNavInput_KeyUp_,        // move up
    773                                 ImGuiNavInput_KeyDown_,      // move down
    774                                 ImGuiNavInput_COUNT,
    775                                 ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_
     1085    // Gamepad Mapping
     1086    ImGuiNavInput_Activate,      // activate / open / toggle / tweak value       // e.g. Cross  (PS4), A (Xbox), A (Switch), Space (Keyboard)
     1087    ImGuiNavInput_Cancel,        // cancel / close / exit                        // e.g. Circle (PS4), B (Xbox), B (Switch), Escape (Keyboard)
     1088    ImGuiNavInput_Input,         // text input / on-screen keyboard              // e.g. Triang.(PS4), Y (Xbox), X (Switch), Return (Keyboard)
     1089    ImGuiNavInput_Menu,          // tap: toggle menu / hold: focus, move, resize // e.g. Square (PS4), X (Xbox), Y (Switch), Alt (Keyboard)
     1090    ImGuiNavInput_DpadLeft,      // move / tweak / resize window (w/ PadMenu)    // e.g. D-pad Left/Right/Up/Down (Gamepads), Arrow keys (Keyboard)
     1091    ImGuiNavInput_DpadRight,     //
     1092    ImGuiNavInput_DpadUp,        //
     1093    ImGuiNavInput_DpadDown,      //
     1094    ImGuiNavInput_LStickLeft,    // scroll / move window (w/ PadMenu)            // e.g. Left Analog Stick Left/Right/Up/Down
     1095    ImGuiNavInput_LStickRight,   //
     1096    ImGuiNavInput_LStickUp,      //
     1097    ImGuiNavInput_LStickDown,    //
     1098    ImGuiNavInput_FocusPrev,     // next window (w/ PadMenu)                     // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
     1099    ImGuiNavInput_FocusNext,     // prev window (w/ PadMenu)                     // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)
     1100    ImGuiNavInput_TweakSlow,     // slower tweaks                                // e.g. L1 or L2 (PS4), LB or LT (Xbox), L or ZL (Switch)
     1101    ImGuiNavInput_TweakFast,     // faster tweaks                                // e.g. R1 or R2 (PS4), RB or RT (Xbox), R or ZL (Switch)
     1102
     1103    // [Internal] Don't use directly! This is used internally to differentiate keyboard from gamepad inputs for behaviors that require to differentiate them.
     1104    // Keyboard behavior that have no corresponding gamepad mapping (e.g. CTRL+TAB) will be directly reading from io.KeysDown[] instead of io.NavInputs[].
     1105    ImGuiNavInput_KeyMenu_,      // toggle menu                                  // = io.KeyAlt
     1106    ImGuiNavInput_KeyLeft_,      // move left                                    // = Arrow keys
     1107    ImGuiNavInput_KeyRight_,     // move right
     1108    ImGuiNavInput_KeyUp_,        // move up
     1109    ImGuiNavInput_KeyDown_,      // move down
     1110    ImGuiNavInput_COUNT,
     1111    ImGuiNavInput_InternalStart_ = ImGuiNavInput_KeyMenu_
    7761112};
    7771113
     
    7791115enum ImGuiConfigFlags_
    7801116{
    781    ImGuiConfigFlags_NavEnableKeyboard = 1 << 0,   // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[].
    782    ImGuiConfigFlags_NavEnableGamepad = 1 << 1,   // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad.
    783    ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2,   // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth.
    784    ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3,   // Instruct navigation to not set the io.WantCaptureKeyboard flag with io.NavActive is set.
    785    ImGuiConfigFlags_NoMouse = 1 << 4,   // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information back-end
    786    ImGuiConfigFlags_NoMouseCursorChange = 1 << 5,   // Instruct back-end to not alter mouse cursor shape and visibility.
    787 
    788                                                     // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core ImGui)
    789                                                     ImGuiConfigFlags_IsSRGB = 1 << 20,  // Application is SRGB-aware.
    790                                                     ImGuiConfigFlags_IsTouchScreen = 1 << 21   // Application is using a touch screen instead of a mouse.
     1117    ImGuiConfigFlags_None                   = 0,
     1118    ImGuiConfigFlags_NavEnableKeyboard      = 1 << 0,   // Master keyboard navigation enable flag. NewFrame() will automatically fill io.NavInputs[] based on io.KeysDown[].
     1119    ImGuiConfigFlags_NavEnableGamepad       = 1 << 1,   // Master gamepad navigation enable flag. This is mostly to instruct your imgui back-end to fill io.NavInputs[]. Back-end also needs to set ImGuiBackendFlags_HasGamepad.
     1120    ImGuiConfigFlags_NavEnableSetMousePos   = 1 << 2,   // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your binding, otherwise ImGui will react as if the mouse is jumping around back and forth.
     1121    ImGuiConfigFlags_NavNoCaptureKeyboard   = 1 << 3,   // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set.
     1122    ImGuiConfigFlags_NoMouse                = 1 << 4,   // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end.
     1123    ImGuiConfigFlags_NoMouseCursorChange    = 1 << 5,   // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.
     1124
     1125    // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core Dear ImGui)
     1126    ImGuiConfigFlags_IsSRGB                 = 1 << 20,  // Application is SRGB-aware.
     1127    ImGuiConfigFlags_IsTouchScreen          = 1 << 21   // Application is using a touch screen instead of a mouse.
    7911128};
    7921129
     
    7941131enum ImGuiBackendFlags_
    7951132{
    796    ImGuiBackendFlags_HasGamepad = 1 << 0,   // Back-end supports and has a connected gamepad.
    797    ImGuiBackendFlags_HasMouseCursors = 1 << 1,   // Back-end supports reading GetMouseCursor() to change the OS cursor shape.
    798    ImGuiBackendFlags_HasSetMousePos = 1 << 2    // Back-end supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set).
     1133    ImGuiBackendFlags_None                  = 0,
     1134    ImGuiBackendFlags_HasGamepad            = 1 << 0,   // Back-end Platform supports gamepad and currently has one connected.
     1135    ImGuiBackendFlags_HasMouseCursors       = 1 << 1,   // Back-end Platform supports honoring GetMouseCursor() value to change the OS cursor shape.
     1136    ImGuiBackendFlags_HasSetMousePos        = 1 << 2,   // Back-end Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set).
     1137    ImGuiBackendFlags_RendererHasVtxOffset  = 1 << 3    // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bit indices.
    7991138};
    8001139
     
    8021141enum ImGuiCol_
    8031142{
    804    ImGuiCol_Text,
    805    ImGuiCol_TextDisabled,
    806    ImGuiCol_WindowBg,              // Background of normal windows
    807    ImGuiCol_ChildBg,               // Background of child windows
    808    ImGuiCol_PopupBg,               // Background of popups, menus, tooltips windows
    809    ImGuiCol_Border,
    810    ImGuiCol_BorderShadow,
    811    ImGuiCol_FrameBg,               // Background of checkbox, radio button, plot, slider, text input
    812    ImGuiCol_FrameBgHovered,
    813    ImGuiCol_FrameBgActive,
    814    ImGuiCol_TitleBg,
    815    ImGuiCol_TitleBgActive,
    816    ImGuiCol_TitleBgCollapsed,
    817    ImGuiCol_MenuBarBg,
    818    ImGuiCol_ScrollbarBg,
    819    ImGuiCol_ScrollbarGrab,
    820    ImGuiCol_ScrollbarGrabHovered,
    821    ImGuiCol_ScrollbarGrabActive,
    822    ImGuiCol_CheckMark,
    823    ImGuiCol_SliderGrab,
    824    ImGuiCol_SliderGrabActive,
    825    ImGuiCol_Button,
    826    ImGuiCol_ButtonHovered,
    827    ImGuiCol_ButtonActive,
    828    ImGuiCol_Header,
    829    ImGuiCol_HeaderHovered,
    830    ImGuiCol_HeaderActive,
    831    ImGuiCol_Separator,
    832    ImGuiCol_SeparatorHovered,
    833    ImGuiCol_SeparatorActive,
    834    ImGuiCol_ResizeGrip,
    835    ImGuiCol_ResizeGripHovered,
    836    ImGuiCol_ResizeGripActive,
    837    ImGuiCol_PlotLines,
    838    ImGuiCol_PlotLinesHovered,
    839    ImGuiCol_PlotHistogram,
    840    ImGuiCol_PlotHistogramHovered,
    841    ImGuiCol_TextSelectedBg,
    842    ImGuiCol_ModalWindowDarkening,  // Darken/colorize entire screen behind a modal window, when one is active
    843    ImGuiCol_DragDropTarget,
    844    ImGuiCol_NavHighlight,          // Gamepad/keyboard: current highlighted item
    845    ImGuiCol_NavWindowingHighlight, // Gamepad/keyboard: when holding NavMenu to focus/move/resize windows
    846    ImGuiCol_COUNT
    847 
    848    // Obsolete names (will be removed)
     1143    ImGuiCol_Text,
     1144    ImGuiCol_TextDisabled,
     1145    ImGuiCol_WindowBg,              // Background of normal windows
     1146    ImGuiCol_ChildBg,               // Background of child windows
     1147    ImGuiCol_PopupBg,               // Background of popups, menus, tooltips windows
     1148    ImGuiCol_Border,
     1149    ImGuiCol_BorderShadow,
     1150    ImGuiCol_FrameBg,               // Background of checkbox, radio button, plot, slider, text input
     1151    ImGuiCol_FrameBgHovered,
     1152    ImGuiCol_FrameBgActive,
     1153    ImGuiCol_TitleBg,
     1154    ImGuiCol_TitleBgActive,
     1155    ImGuiCol_TitleBgCollapsed,
     1156    ImGuiCol_MenuBarBg,
     1157    ImGuiCol_ScrollbarBg,
     1158    ImGuiCol_ScrollbarGrab,
     1159    ImGuiCol_ScrollbarGrabHovered,
     1160    ImGuiCol_ScrollbarGrabActive,
     1161    ImGuiCol_CheckMark,
     1162    ImGuiCol_SliderGrab,
     1163    ImGuiCol_SliderGrabActive,
     1164    ImGuiCol_Button,
     1165    ImGuiCol_ButtonHovered,
     1166    ImGuiCol_ButtonActive,
     1167    ImGuiCol_Header,                // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem
     1168    ImGuiCol_HeaderHovered,
     1169    ImGuiCol_HeaderActive,
     1170    ImGuiCol_Separator,
     1171    ImGuiCol_SeparatorHovered,
     1172    ImGuiCol_SeparatorActive,
     1173    ImGuiCol_ResizeGrip,
     1174    ImGuiCol_ResizeGripHovered,
     1175    ImGuiCol_ResizeGripActive,
     1176    ImGuiCol_Tab,
     1177    ImGuiCol_TabHovered,
     1178    ImGuiCol_TabActive,
     1179    ImGuiCol_TabUnfocused,
     1180    ImGuiCol_TabUnfocusedActive,
     1181    ImGuiCol_PlotLines,
     1182    ImGuiCol_PlotLinesHovered,
     1183    ImGuiCol_PlotHistogram,
     1184    ImGuiCol_PlotHistogramHovered,
     1185    ImGuiCol_TextSelectedBg,
     1186    ImGuiCol_DragDropTarget,
     1187    ImGuiCol_NavHighlight,          // Gamepad/keyboard: current highlighted item
     1188    ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB
     1189    ImGuiCol_NavWindowingDimBg,     // Darken/colorize entire screen behind the CTRL+TAB window list, when active
     1190    ImGuiCol_ModalWindowDimBg,      // Darken/colorize entire screen behind a modal window, when one is active
     1191    ImGuiCol_COUNT
     1192
     1193    // Obsolete names (will be removed)
    8491194#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    850    , ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg, ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive
    851    //ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered, // [unused since 1.60+] the close button now uses regular button colors.
    852    //ImGuiCol_ComboBg,                                                              // [unused since 1.53+] ComboBg has been merged with PopupBg, so a redirect isn't accurate.
     1195    , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg                      // [renamed in 1.63]
     1196    //, ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered// [unused since 1.60+] the close button now uses regular button colors.
    8531197#endif
    8541198};
    8551199
    8561200// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure.
    857 // NB: the enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code. During initialization, feel free to just poke into ImGuiStyle directly.
    858 // NB: if changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type.
     1201// - The enum only refers to fields of ImGuiStyle which makes sense to be pushed/popped inside UI code.
     1202//   During initialization or between frames, feel free to just poke into ImGuiStyle directly.
     1203// - Tip: Use your programming IDE navigation facilities on the names in the _second column_ below to find the actual members and their description.
     1204//   In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
     1205//   With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
     1206// - When changing this enum, you need to update the associated internal table GStyleVarInfo[] accordingly. This is where we link enum values to members offset/type.
    8591207enum ImGuiStyleVar_
    8601208{
    861    // Enum name ......................// Member in ImGuiStyle structure (see ImGuiStyle for descriptions)
    862    ImGuiStyleVar_Alpha,               // float     Alpha
    863    ImGuiStyleVar_WindowPadding,       // ImVec2    WindowPadding
    864    ImGuiStyleVar_WindowRounding,      // float     WindowRounding
    865    ImGuiStyleVar_WindowBorderSize,    // float     WindowBorderSize
    866    ImGuiStyleVar_WindowMinSize,       // ImVec2    WindowMinSize
    867    ImGuiStyleVar_WindowTitleAlign,    // ImVec2    WindowTitleAlign
    868    ImGuiStyleVar_ChildRounding,       // float     ChildRounding
    869    ImGuiStyleVar_ChildBorderSize,     // float     ChildBorderSize
    870    ImGuiStyleVar_PopupRounding,       // float     PopupRounding
    871    ImGuiStyleVar_PopupBorderSize,     // float     PopupBorderSize
    872    ImGuiStyleVar_FramePadding,        // ImVec2    FramePadding
    873    ImGuiStyleVar_FrameRounding,       // float     FrameRounding
    874    ImGuiStyleVar_FrameBorderSize,     // float     FrameBorderSize
    875    ImGuiStyleVar_ItemSpacing,         // ImVec2    ItemSpacing
    876    ImGuiStyleVar_ItemInnerSpacing,    // ImVec2    ItemInnerSpacing
    877    ImGuiStyleVar_IndentSpacing,       // float     IndentSpacing
    878    ImGuiStyleVar_ScrollbarSize,       // float     ScrollbarSize
    879    ImGuiStyleVar_ScrollbarRounding,   // float     ScrollbarRounding
    880    ImGuiStyleVar_GrabMinSize,         // float     GrabMinSize
    881    ImGuiStyleVar_GrabRounding,        // float     GrabRounding
    882    ImGuiStyleVar_ButtonTextAlign,     // ImVec2    ButtonTextAlign
    883    ImGuiStyleVar_COUNT
    884 
    885    // Obsolete names (will be removed)
     1209    // Enum name --------------------- // Member in ImGuiStyle structure (see ImGuiStyle for descriptions)
     1210    ImGuiStyleVar_Alpha,               // float     Alpha
     1211    ImGuiStyleVar_WindowPadding,       // ImVec2    WindowPadding
     1212    ImGuiStyleVar_WindowRounding,      // float     WindowRounding
     1213    ImGuiStyleVar_WindowBorderSize,    // float     WindowBorderSize
     1214    ImGuiStyleVar_WindowMinSize,       // ImVec2    WindowMinSize
     1215    ImGuiStyleVar_WindowTitleAlign,    // ImVec2    WindowTitleAlign
     1216    ImGuiStyleVar_ChildRounding,       // float     ChildRounding
     1217    ImGuiStyleVar_ChildBorderSize,     // float     ChildBorderSize
     1218    ImGuiStyleVar_PopupRounding,       // float     PopupRounding
     1219    ImGuiStyleVar_PopupBorderSize,     // float     PopupBorderSize
     1220    ImGuiStyleVar_FramePadding,        // ImVec2    FramePadding
     1221    ImGuiStyleVar_FrameRounding,       // float     FrameRounding
     1222    ImGuiStyleVar_FrameBorderSize,     // float     FrameBorderSize
     1223    ImGuiStyleVar_ItemSpacing,         // ImVec2    ItemSpacing
     1224    ImGuiStyleVar_ItemInnerSpacing,    // ImVec2    ItemInnerSpacing
     1225    ImGuiStyleVar_IndentSpacing,       // float     IndentSpacing
     1226    ImGuiStyleVar_ScrollbarSize,       // float     ScrollbarSize
     1227    ImGuiStyleVar_ScrollbarRounding,   // float     ScrollbarRounding
     1228    ImGuiStyleVar_GrabMinSize,         // float     GrabMinSize
     1229    ImGuiStyleVar_GrabRounding,        // float     GrabRounding
     1230    ImGuiStyleVar_TabRounding,         // float     TabRounding
     1231    ImGuiStyleVar_ButtonTextAlign,     // ImVec2    ButtonTextAlign
     1232    ImGuiStyleVar_SelectableTextAlign, // ImVec2    SelectableTextAlign
     1233    ImGuiStyleVar_COUNT
     1234
     1235    // Obsolete names (will be removed)
    8861236#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    887    , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT, ImGuiStyleVar_ChildWindowRounding = ImGuiStyleVar_ChildRounding
    888 #endif
    889 };
    890 
    891 // Enumeration for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton()
     1237    , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT                    // [renamed in 1.60]
     1238#endif
     1239};
     1240
     1241// Flags for InvisibleButton() [extended in imgui_internal.h]
     1242enum ImGuiButtonFlags_
     1243{
     1244    ImGuiButtonFlags_None                   = 0,
     1245    ImGuiButtonFlags_MouseButtonLeft        = 1 << 0,   // React on left mouse button (default)
     1246    ImGuiButtonFlags_MouseButtonRight       = 1 << 1,   // React on right mouse button
     1247    ImGuiButtonFlags_MouseButtonMiddle      = 1 << 2,   // React on center mouse button
     1248
     1249    // [Internal]
     1250    ImGuiButtonFlags_MouseButtonMask_       = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle,
     1251    ImGuiButtonFlags_MouseButtonDefault_    = ImGuiButtonFlags_MouseButtonLeft
     1252};
     1253
     1254// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton()
    8921255enum ImGuiColorEditFlags_
    8931256{
    894    ImGuiColorEditFlags_NoAlpha = 1 << 1,   //              // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (read 3 components from the input pointer).
    895    ImGuiColorEditFlags_NoPicker = 1 << 2,   //              // ColorEdit: disable picker when clicking on colored square.
    896    ImGuiColorEditFlags_NoOptions = 1 << 3,   //              // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview.
    897    ImGuiColorEditFlags_NoSmallPreview = 1 << 4,   //              // ColorEdit, ColorPicker: disable colored square preview next to the inputs. (e.g. to show only the inputs)
    898    ImGuiColorEditFlags_NoInputs = 1 << 5,   //              // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview colored square).
    899    ImGuiColorEditFlags_NoTooltip = 1 << 6,   //              // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview.
    900    ImGuiColorEditFlags_NoLabel = 1 << 7,   //              // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker).
    901    ImGuiColorEditFlags_NoSidePreview = 1 << 8,   //              // ColorPicker: disable bigger color preview on right side of the picker, use small colored square preview instead.
    902 
    903                                                  // User Options (right-click on widget to change some of them). You can set application defaults using SetColorEditOptions(). The idea is that you probably don't want to override them in most of your calls, let the user choose and/or call SetColorEditOptions() during startup.
    904                                                  ImGuiColorEditFlags_AlphaBar = 1 << 9,   //              // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker.
    905                                                  ImGuiColorEditFlags_AlphaPreview = 1 << 10,  //              // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque.
    906                                                  ImGuiColorEditFlags_AlphaPreviewHalf = 1 << 11,  //              // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque.
    907                                                  ImGuiColorEditFlags_HDR = 1 << 12,  //              // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well).
    908                                                  ImGuiColorEditFlags_RGB = 1 << 13,  // [Inputs]     // ColorEdit: choose one among RGB/HSV/HEX. ColorPicker: choose any combination using RGB/HSV/HEX.
    909                                                  ImGuiColorEditFlags_HSV = 1 << 14,  // [Inputs]     // "
    910                                                  ImGuiColorEditFlags_HEX = 1 << 15,  // [Inputs]     // "
    911                                                  ImGuiColorEditFlags_Uint8 = 1 << 16,  // [DataType]   // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255.
    912                                                  ImGuiColorEditFlags_Float = 1 << 17,  // [DataType]   // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers.
    913                                                  ImGuiColorEditFlags_PickerHueBar = 1 << 18,  // [PickerMode] // ColorPicker: bar for Hue, rectangle for Sat/Value.
    914                                                  ImGuiColorEditFlags_PickerHueWheel = 1 << 19,  // [PickerMode] // ColorPicker: wheel for Hue, triangle for Sat/Value.
    915 
    916                                                                                                 // [Internal] Masks
    917                                                                                                 ImGuiColorEditFlags__InputsMask = ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_HSV | ImGuiColorEditFlags_HEX,
    918                                                                                                 ImGuiColorEditFlags__DataTypeMask = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float,
    919                                                                                                 ImGuiColorEditFlags__PickerMask = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar,
    920                                                                                                 ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_PickerHueBar    // Change application default using SetColorEditOptions()
     1257    ImGuiColorEditFlags_None            = 0,
     1258    ImGuiColorEditFlags_NoAlpha         = 1 << 1,   //              // ColorEdit, ColorPicker, ColorButton: ignore Alpha component (will only read 3 components from the input pointer).
     1259    ImGuiColorEditFlags_NoPicker        = 1 << 2,   //              // ColorEdit: disable picker when clicking on colored square.
     1260    ImGuiColorEditFlags_NoOptions       = 1 << 3,   //              // ColorEdit: disable toggling options menu when right-clicking on inputs/small preview.
     1261    ImGuiColorEditFlags_NoSmallPreview  = 1 << 4,   //              // ColorEdit, ColorPicker: disable colored square preview next to the inputs. (e.g. to show only the inputs)
     1262    ImGuiColorEditFlags_NoInputs        = 1 << 5,   //              // ColorEdit, ColorPicker: disable inputs sliders/text widgets (e.g. to show only the small preview colored square).
     1263    ImGuiColorEditFlags_NoTooltip       = 1 << 6,   //              // ColorEdit, ColorPicker, ColorButton: disable tooltip when hovering the preview.
     1264    ImGuiColorEditFlags_NoLabel         = 1 << 7,   //              // ColorEdit, ColorPicker: disable display of inline text label (the label is still forwarded to the tooltip and picker).
     1265    ImGuiColorEditFlags_NoSidePreview   = 1 << 8,   //              // ColorPicker: disable bigger color preview on right side of the picker, use small colored square preview instead.
     1266    ImGuiColorEditFlags_NoDragDrop      = 1 << 9,   //              // ColorEdit: disable drag and drop target. ColorButton: disable drag and drop source.
     1267    ImGuiColorEditFlags_NoBorder        = 1 << 10,  //              // ColorButton: disable border (which is enforced by default)
     1268
     1269    // User Options (right-click on widget to change some of them).
     1270    ImGuiColorEditFlags_AlphaBar        = 1 << 16,  //              // ColorEdit, ColorPicker: show vertical alpha bar/gradient in picker.
     1271    ImGuiColorEditFlags_AlphaPreview    = 1 << 17,  //              // ColorEdit, ColorPicker, ColorButton: display preview as a transparent color over a checkerboard, instead of opaque.
     1272    ImGuiColorEditFlags_AlphaPreviewHalf= 1 << 18,  //              // ColorEdit, ColorPicker, ColorButton: display half opaque / half checkerboard, instead of opaque.
     1273    ImGuiColorEditFlags_HDR             = 1 << 19,  //              // (WIP) ColorEdit: Currently only disable 0.0f..1.0f limits in RGBA edition (note: you probably want to use ImGuiColorEditFlags_Float flag as well).
     1274    ImGuiColorEditFlags_DisplayRGB      = 1 << 20,  // [Display]    // ColorEdit: override _display_ type among RGB/HSV/Hex. ColorPicker: select any combination using one or more of RGB/HSV/Hex.
     1275    ImGuiColorEditFlags_DisplayHSV      = 1 << 21,  // [Display]    // "
     1276    ImGuiColorEditFlags_DisplayHex      = 1 << 22,  // [Display]    // "
     1277    ImGuiColorEditFlags_Uint8           = 1 << 23,  // [DataType]   // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0..255.
     1278    ImGuiColorEditFlags_Float           = 1 << 24,  // [DataType]   // ColorEdit, ColorPicker, ColorButton: _display_ values formatted as 0.0f..1.0f floats instead of 0..255 integers. No round-trip of value via integers.
     1279    ImGuiColorEditFlags_PickerHueBar    = 1 << 25,  // [Picker]     // ColorPicker: bar for Hue, rectangle for Sat/Value.
     1280    ImGuiColorEditFlags_PickerHueWheel  = 1 << 26,  // [Picker]     // ColorPicker: wheel for Hue, triangle for Sat/Value.
     1281    ImGuiColorEditFlags_InputRGB        = 1 << 27,  // [Input]      // ColorEdit, ColorPicker: input and output data in RGB format.
     1282    ImGuiColorEditFlags_InputHSV        = 1 << 28,  // [Input]      // ColorEdit, ColorPicker: input and output data in HSV format.
     1283
     1284    // Defaults Options. You can set application defaults using SetColorEditOptions(). The intent is that you probably don't want to
     1285    // override them in most of your calls. Let the user choose via the option menu and/or call SetColorEditOptions() once during startup.
     1286    ImGuiColorEditFlags__OptionsDefault = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_PickerHueBar,
     1287
     1288    // [Internal] Masks
     1289    ImGuiColorEditFlags__DisplayMask    = ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_DisplayHex,
     1290    ImGuiColorEditFlags__DataTypeMask   = ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_Float,
     1291    ImGuiColorEditFlags__PickerMask     = ImGuiColorEditFlags_PickerHueWheel | ImGuiColorEditFlags_PickerHueBar,
     1292    ImGuiColorEditFlags__InputMask      = ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_InputHSV
     1293
     1294    // Obsolete names (will be removed)
     1295#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     1296    , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex  // [renamed in 1.69]
     1297#endif
     1298};
     1299
     1300// Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc.
     1301// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them.
     1302enum ImGuiSliderFlags_
     1303{
     1304    ImGuiSliderFlags_None                   = 0,
     1305    ImGuiSliderFlags_AlwaysClamp            = 1 << 4,       // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
     1306    ImGuiSliderFlags_Logarithmic            = 1 << 5,       // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits.
     1307    ImGuiSliderFlags_NoRoundToFormat        = 1 << 6,       // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits)
     1308    ImGuiSliderFlags_NoInput                = 1 << 7,       // Disable CTRL+Click or Enter key allowing to input text directly into the widget
     1309    ImGuiSliderFlags_InvalidMask_           = 0x7000000F    // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
     1310
     1311    // Obsolete names (will be removed)
     1312#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     1313    , ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp // [renamed in 1.79]
     1314#endif
     1315};
     1316
     1317// Identify a mouse button.
     1318// Those values are guaranteed to be stable and we frequently use 0/1 directly. Named enums provided for convenience.
     1319enum ImGuiMouseButton_
     1320{
     1321    ImGuiMouseButton_Left = 0,
     1322    ImGuiMouseButton_Right = 1,
     1323    ImGuiMouseButton_Middle = 2,
     1324    ImGuiMouseButton_COUNT = 5
    9211325};
    9221326
     
    9251329enum ImGuiMouseCursor_
    9261330{
    927    ImGuiMouseCursor_None = -1,
    928    ImGuiMouseCursor_Arrow = 0,
    929    ImGuiMouseCursor_TextInput,         // When hovering over InputText, etc.
    930    ImGuiMouseCursor_ResizeAll,         // Unused by imgui functions
    931    ImGuiMouseCursor_ResizeNS,          // When hovering over an horizontal border
    932    ImGuiMouseCursor_ResizeEW,          // When hovering over a vertical border or a column
    933    ImGuiMouseCursor_ResizeNESW,        // When hovering over the bottom-left corner of a window
    934    ImGuiMouseCursor_ResizeNWSE,        // When hovering over the bottom-right corner of a window
    935    ImGuiMouseCursor_COUNT
    936 
    937    // Obsolete names (will be removed)
     1331    ImGuiMouseCursor_None = -1,
     1332    ImGuiMouseCursor_Arrow = 0,
     1333    ImGuiMouseCursor_TextInput,         // When hovering over InputText, etc.
     1334    ImGuiMouseCursor_ResizeAll,         // (Unused by Dear ImGui functions)
     1335    ImGuiMouseCursor_ResizeNS,          // When hovering over an horizontal border
     1336    ImGuiMouseCursor_ResizeEW,          // When hovering over a vertical border or a column
     1337    ImGuiMouseCursor_ResizeNESW,        // When hovering over the bottom-left corner of a window
     1338    ImGuiMouseCursor_ResizeNWSE,        // When hovering over the bottom-right corner of a window
     1339    ImGuiMouseCursor_Hand,              // (Unused by Dear ImGui functions. Use for e.g. hyperlinks)
     1340    ImGuiMouseCursor_NotAllowed,        // When hovering something with disallowed interaction. Usually a crossed circle.
     1341    ImGuiMouseCursor_COUNT
     1342
     1343    // Obsolete names (will be removed)
    9381344#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    939    , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT
    940 #endif
    941 };
    942 
    943 // Condition for ImGui::SetWindow***(), SetNextWindow***(), SetNextTreeNode***() functions
    944 // Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always.
     1345    , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT      // [renamed in 1.60]
     1346#endif
     1347};
     1348
     1349// Enumeration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions
     1350// Represent a condition.
     1351// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always.
    9451352enum ImGuiCond_
    9461353{
    947    ImGuiCond_Always = 1 << 0,   // Set the variable
    948    ImGuiCond_Once = 1 << 1,   // Set the variable once per runtime session (only the first call with succeed)
    949    ImGuiCond_FirstUseEver = 1 << 2,   // Set the variable if the object/window has no persistently saved data (no entry in .ini file)
    950    ImGuiCond_Appearing = 1 << 3    // Set the variable if the object/window is appearing after being hidden/inactive (or the first time)
    951 
    952                                    // Obsolete names (will be removed)
     1354    ImGuiCond_None          = 0,        // No condition (always set the variable), same as _Always
     1355    ImGuiCond_Always        = 1 << 0,   // No condition (always set the variable)
     1356    ImGuiCond_Once          = 1 << 1,   // Set the variable once per runtime session (only the first call will succeed)
     1357    ImGuiCond_FirstUseEver  = 1 << 2,   // Set the variable if the object/window has no persistently saved data (no entry in .ini file)
     1358    ImGuiCond_Appearing     = 1 << 3    // Set the variable if the object/window is appearing after being hidden/inactive (or the first time)
     1359};
     1360
     1361//-----------------------------------------------------------------------------
     1362// Helpers: Memory allocations macros
     1363// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()
     1364// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
     1365// Defining a custom placement new() with a custom parameter allows us to bypass including <new> which on some platforms complains when user has disabled exceptions.
     1366//-----------------------------------------------------------------------------
     1367
     1368struct ImNewWrapper {};
     1369inline void* operator new(size_t, ImNewWrapper, void* ptr) { return ptr; }
     1370inline void  operator delete(void*, ImNewWrapper, void*)   {} // This is only required so we can use the symmetrical new()
     1371#define IM_ALLOC(_SIZE)                     ImGui::MemAlloc(_SIZE)
     1372#define IM_FREE(_PTR)                       ImGui::MemFree(_PTR)
     1373#define IM_PLACEMENT_NEW(_PTR)              new(ImNewWrapper(), _PTR)
     1374#define IM_NEW(_TYPE)                       new(ImNewWrapper(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
     1375template<typename T> void IM_DELETE(T* p)   { if (p) { p->~T(); ImGui::MemFree(p); } }
     1376
     1377//-----------------------------------------------------------------------------
     1378// Helper: ImVector<>
     1379// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
     1380//-----------------------------------------------------------------------------
     1381// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it.
     1382// - We use std-like naming convention here, which is a little unusual for this codebase.
     1383// - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs.
     1384// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that,
     1385//   Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.
     1386//-----------------------------------------------------------------------------
     1387
     1388template<typename T>
     1389struct ImVector
     1390{
     1391    int                 Size;
     1392    int                 Capacity;
     1393    T*                  Data;
     1394
     1395    // Provide standard typedefs but we don't use them ourselves.
     1396    typedef T                   value_type;
     1397    typedef value_type*         iterator;
     1398    typedef const value_type*   const_iterator;
     1399
     1400    // Constructors, destructor
     1401    inline ImVector()                                       { Size = Capacity = 0; Data = NULL; }
     1402    inline ImVector(const ImVector<T>& src)                 { Size = Capacity = 0; Data = NULL; operator=(src); }
     1403    inline ImVector<T>& operator=(const ImVector<T>& src)   { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(T)); return *this; }
     1404    inline ~ImVector()                                      { if (Data) IM_FREE(Data); }
     1405
     1406    inline bool         empty() const                       { return Size == 0; }
     1407    inline int          size() const                        { return Size; }
     1408    inline int          size_in_bytes() const               { return Size * (int)sizeof(T); }
     1409    inline int          max_size() const                    { return 0x7FFFFFFF / (int)sizeof(T); }
     1410    inline int          capacity() const                    { return Capacity; }
     1411    inline T&           operator[](int i)                   { IM_ASSERT(i >= 0 && i < Size); return Data[i]; }
     1412    inline const T&     operator[](int i) const             { IM_ASSERT(i >= 0 && i < Size); return Data[i]; }
     1413
     1414    inline void         clear()                             { if (Data) { Size = Capacity = 0; IM_FREE(Data); Data = NULL; } }
     1415    inline T*           begin()                             { return Data; }
     1416    inline const T*     begin() const                       { return Data; }
     1417    inline T*           end()                               { return Data + Size; }
     1418    inline const T*     end() const                         { return Data + Size; }
     1419    inline T&           front()                             { IM_ASSERT(Size > 0); return Data[0]; }
     1420    inline const T&     front() const                       { IM_ASSERT(Size > 0); return Data[0]; }
     1421    inline T&           back()                              { IM_ASSERT(Size > 0); return Data[Size - 1]; }
     1422    inline const T&     back() const                        { IM_ASSERT(Size > 0); return Data[Size - 1]; }
     1423    inline void         swap(ImVector<T>& rhs)              { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; T* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
     1424
     1425    inline int          _grow_capacity(int sz) const        { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; }
     1426    inline void         resize(int new_size)                { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
     1427    inline void         resize(int new_size, const T& v)    { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
     1428    inline void         shrink(int new_size)                { IM_ASSERT(new_size <= Size); Size = new_size; } // Resize a vector to a smaller size, guaranteed not to cause a reallocation
     1429    inline void         reserve(int new_capacity)           { if (new_capacity <= Capacity) return; T* new_data = (T*)IM_ALLOC((size_t)new_capacity * sizeof(T)); if (Data) { memcpy(new_data, Data, (size_t)Size * sizeof(T)); IM_FREE(Data); } Data = new_data; Capacity = new_capacity; }
     1430
     1431    // NB: It is illegal to call push_back/push_front/insert with a reference pointing inside the ImVector data itself! e.g. v.push_back(v[10]) is forbidden.
     1432    inline void         push_back(const T& v)               { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
     1433    inline void         pop_back()                          { IM_ASSERT(Size > 0); Size--; }
     1434    inline void         push_front(const T& v)              { if (Size == 0) push_back(v); else insert(Data, v); }
     1435    inline T*           erase(const T* it)                  { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(T)); Size--; return Data + off; }
     1436    inline T*           erase(const T* it, const T* it_last){ IM_ASSERT(it >= Data && it < Data + Size && it_last > it && it_last <= Data + Size); const ptrdiff_t count = it_last - it; const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + count, ((size_t)Size - (size_t)off - count) * sizeof(T)); Size -= (int)count; return Data + off; }
     1437    inline T*           erase_unsorted(const T* it)         { IM_ASSERT(it >= Data && it < Data + Size);  const ptrdiff_t off = it - Data; if (it < Data + Size - 1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; }
     1438    inline T*           insert(const T* it, const T& v)     { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; }
     1439    inline bool         contains(const T& v) const          { const T* data = Data;  const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }
     1440    inline T*           find(const T& v)                    { T* data = Data;  const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; }
     1441    inline const T*     find(const T& v) const              { const T* data = Data;  const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; }
     1442    inline bool         find_erase(const T& v)              { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; }
     1443    inline bool         find_erase_unsorted(const T& v)     { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; }
     1444    inline int          index_from_ptr(const T* it) const   { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; return (int)off; }
     1445};
     1446
     1447//-----------------------------------------------------------------------------
     1448// ImGuiStyle
     1449// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame().
     1450// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values,
     1451// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors.
     1452//-----------------------------------------------------------------------------
     1453
     1454struct ImGuiStyle
     1455{
     1456    float       Alpha;                      // Global alpha applies to everything in Dear ImGui.
     1457    ImVec2      WindowPadding;              // Padding within a window.
     1458    float       WindowRounding;             // 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.
     1459    float       WindowBorderSize;           // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
     1460    ImVec2      WindowMinSize;              // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints().
     1461    ImVec2      WindowTitleAlign;           // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered.
     1462    ImGuiDir    WindowMenuButtonPosition;   // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left.
     1463    float       ChildRounding;              // Radius of child window corners rounding. Set to 0.0f to have rectangular windows.
     1464    float       ChildBorderSize;            // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
     1465    float       PopupRounding;              // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding)
     1466    float       PopupBorderSize;            // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
     1467    ImVec2      FramePadding;               // Padding within a framed rectangle (used by most widgets).
     1468    float       FrameRounding;              // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets).
     1469    float       FrameBorderSize;            // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
     1470    ImVec2      ItemSpacing;                // Horizontal and vertical spacing between widgets/lines.
     1471    ImVec2      ItemInnerSpacing;           // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label).
     1472    ImVec2      TouchExtraPadding;          // 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!
     1473    float       IndentSpacing;              // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
     1474    float       ColumnsMinSpacing;          // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
     1475    float       ScrollbarSize;              // Width of the vertical scrollbar, Height of the horizontal scrollbar.
     1476    float       ScrollbarRounding;          // Radius of grab corners for scrollbar.
     1477    float       GrabMinSize;                // Minimum width/height of a grab box for slider/scrollbar.
     1478    float       GrabRounding;               // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
     1479    float       LogSliderDeadzone;          // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
     1480    float       TabRounding;                // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
     1481    float       TabBorderSize;              // Thickness of border around tabs.
     1482    float       TabMinWidthForCloseButton;  // 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.
     1483    ImGuiDir    ColorButtonPosition;        // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
     1484    ImVec2      ButtonTextAlign;            // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
     1485    ImVec2      SelectableTextAlign;        // 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.
     1486    ImVec2      DisplayWindowPadding;       // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
     1487    ImVec2      DisplaySafeAreaPadding;     // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!
     1488    float       MouseCursorScale;           // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
     1489    bool        AntiAliasedLines;           // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList).
     1490    bool        AntiAliasedLinesUseTex;     // Enable anti-aliased lines/borders using textures where possible. Require back-end to render with bilinear filtering. Latched at the beginning of the frame (copied to ImDrawList).
     1491    bool        AntiAliasedFill;            // Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList).
     1492    float       CurveTessellationTol;       // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
     1493    float       CircleSegmentMaxError;      // 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.
     1494    ImVec4      Colors[ImGuiCol_COUNT];
     1495
     1496    IMGUI_API ImGuiStyle();
     1497    IMGUI_API void ScaleAllSizes(float scale_factor);
     1498};
     1499
     1500//-----------------------------------------------------------------------------
     1501// ImGuiIO
     1502// Communicate most settings and inputs/outputs to Dear ImGui using this structure.
     1503// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage.
     1504//-----------------------------------------------------------------------------
     1505
     1506struct ImGuiIO
     1507{
     1508    //------------------------------------------------------------------
     1509    // Configuration (fill once)                // Default value
     1510    //------------------------------------------------------------------
     1511
     1512    ImGuiConfigFlags   ConfigFlags;             // = 0              // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc.
     1513    ImGuiBackendFlags  BackendFlags;            // = 0              // See ImGuiBackendFlags_ enum. Set by back-end (imgui_impl_xxx files or custom back-end) to communicate features supported by the back-end.
     1514    ImVec2      DisplaySize;                    // <unset>          // Main display size, in pixels.
     1515    float       DeltaTime;                      // = 1.0f/60.0f     // Time elapsed since last frame, in seconds.
     1516    float       IniSavingRate;                  // = 5.0f           // Minimum time between saving positions/sizes to .ini file, in seconds.
     1517    const char* IniFilename;                    // = "imgui.ini"    // Path to .ini file. Set NULL to disable automatic .ini loading/saving, if e.g. you want to manually load/save from memory.
     1518    const char* LogFilename;                    // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
     1519    float       MouseDoubleClickTime;           // = 0.30f          // Time for a double-click, in seconds.
     1520    float       MouseDoubleClickMaxDist;        // = 6.0f           // Distance threshold to stay in to validate a double-click, in pixels.
     1521    float       MouseDragThreshold;             // = 6.0f           // Distance threshold before considering we are dragging.
     1522    int         KeyMap[ImGuiKey_COUNT];         // <unset>          // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state.
     1523    float       KeyRepeatDelay;                 // = 0.250f         // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.).
     1524    float       KeyRepeatRate;                  // = 0.050f         // When holding a key/button, rate at which it repeats, in seconds.
     1525    void*       UserData;                       // = NULL           // Store your own data for retrieval by callbacks.
     1526
     1527    ImFontAtlas*Fonts;                          // <auto>           // Font atlas: load, rasterize and pack one or more fonts into a single texture.
     1528    float       FontGlobalScale;                // = 1.0f           // Global scale all fonts
     1529    bool        FontAllowUserScaling;           // = false          // Allow user scaling text of individual window with CTRL+Wheel.
     1530    ImFont*     FontDefault;                    // = NULL           // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0].
     1531    ImVec2      DisplayFramebufferScale;        // = (1, 1)         // For retina display or other situations where window coordinates are different from framebuffer coordinates. This generally ends up in ImDrawData::FramebufferScale.
     1532
     1533    // Miscellaneous options
     1534    bool        MouseDrawCursor;                // = false          // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations.
     1535    bool        ConfigMacOSXBehaviors;          // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63)
     1536    bool        ConfigInputTextCursorBlink;     // = true           // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63)
     1537    bool        ConfigWindowsResizeFromEdges;   // = true           // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag)
     1538    bool        ConfigWindowsMoveFromTitleBarOnly; // = false       // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected.
     1539    float       ConfigWindowsMemoryCompactTimer;// = 60.0f          // [BETA] Compact window memory usage when unused. Set to -1.0f to disable.
     1540
     1541    //------------------------------------------------------------------
     1542    // Platform Functions
     1543    // (the imgui_impl_xxxx back-end files are setting those up for you)
     1544    //------------------------------------------------------------------
     1545
     1546    // Optional: Platform/Renderer back-end name (informational only! will be displayed in About Window) + User data for back-end/wrappers to store their own stuff.
     1547    const char* BackendPlatformName;            // = NULL
     1548    const char* BackendRendererName;            // = NULL
     1549    void*       BackendPlatformUserData;        // = NULL           // User data for platform back-end
     1550    void*       BackendRendererUserData;        // = NULL           // User data for renderer back-end
     1551    void*       BackendLanguageUserData;        // = NULL           // User data for non C++ programming language back-end
     1552
     1553    // Optional: Access OS clipboard
     1554    // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures)
     1555    const char* (*GetClipboardTextFn)(void* user_data);
     1556    void        (*SetClipboardTextFn)(void* user_data, const char* text);
     1557    void*       ClipboardUserData;
     1558
     1559    // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows)
     1560    // (default to use native imm32 api on Windows)
     1561    void        (*ImeSetInputScreenPosFn)(int x, int y);
     1562    void*       ImeWindowHandle;                // = NULL           // (Windows) Set this to your HWND to get automatic IME cursor positioning.
     1563
    9531564#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    954    , ImGuiSetCond_Always = ImGuiCond_Always, ImGuiSetCond_Once = ImGuiCond_Once, ImGuiSetCond_FirstUseEver = ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing = ImGuiCond_Appearing
    955 #endif
    956 };
    957 
    958 // You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame().
    959 // During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values, and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors.
    960 struct ImGuiStyle
    961 {
    962    float       Alpha;                      // Global alpha applies to everything in ImGui.
    963    ImVec2      WindowPadding;              // Padding within a window.
    964    float       WindowRounding;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows.
    965    float       WindowBorderSize;           // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
    966    ImVec2      WindowMinSize;              // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints().
    967    ImVec2      WindowTitleAlign;           // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered.
    968    float       ChildRounding;              // Radius of child window corners rounding. Set to 0.0f to have rectangular windows.
    969    float       ChildBorderSize;            // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
    970    float       PopupRounding;              // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding)
    971    float       PopupBorderSize;            // Thickness of border around popup/tooltip windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
    972    ImVec2      FramePadding;               // Padding within a framed rectangle (used by most widgets).
    973    float       FrameRounding;              // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets).
    974    float       FrameBorderSize;            // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
    975    ImVec2      ItemSpacing;                // Horizontal and vertical spacing between widgets/lines.
    976    ImVec2      ItemInnerSpacing;           // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label).
    977    ImVec2      TouchExtraPadding;          // 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!
    978    float       IndentSpacing;              // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
    979    float       ColumnsMinSpacing;          // Minimum horizontal spacing between two columns.
    980    float       ScrollbarSize;              // Width of the vertical scrollbar, Height of the horizontal scrollbar.
    981    float       ScrollbarRounding;          // Radius of grab corners for scrollbar.
    982    float       GrabMinSize;                // Minimum width/height of a grab box for slider/scrollbar.
    983    float       GrabRounding;               // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
    984    ImVec2      ButtonTextAlign;            // Alignment of button text when button is larger than text. Defaults to (0.5f,0.5f) for horizontally+vertically centered.
    985    ImVec2      DisplayWindowPadding;       // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
    986    ImVec2      DisplaySafeAreaPadding;     // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!
    987    float       MouseCursorScale;           // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
    988    bool        AntiAliasedLines;           // Enable anti-aliasing on lines/borders. Disable if you are really tight on CPU/GPU.
    989    bool        AntiAliasedFill;            // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
    990    float       CurveTessellationTol;       // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
    991    ImVec4      Colors[ImGuiCol_COUNT];
    992 
    993    IMGUI_API ImGuiStyle();
    994    IMGUI_API void ScaleAllSizes(float scale_factor);
    995 };
    996 
    997 // This is where your app communicate with ImGui. Access via ImGui::GetIO().
    998 // Read 'Programmer guide' section in .cpp file for general usage.
    999 struct ImGuiIO
    1000 {
    1001    //------------------------------------------------------------------
    1002    // Settings (fill once)                 // Default value:
    1003    //------------------------------------------------------------------
    1004 
    1005    ImGuiConfigFlags   ConfigFlags;         // = 0                  // See ImGuiConfigFlags_ enum. Set by user/application. Gamepad/keyboard navigation options, etc.
    1006    ImGuiBackendFlags  BackendFlags;        // = 0                  // Set ImGuiBackendFlags_ enum. Set by imgui_impl_xxx files or custom back-end.
    1007    ImVec2        DisplaySize;              // <unset>              // Display size, in pixels. For clamping windows positions.
    1008    float         DeltaTime;                // = 1.0f/60.0f         // Time elapsed since last frame, in seconds.
    1009    float         IniSavingRate;            // = 5.0f               // Maximum time between saving positions/sizes to .ini file, in seconds.
    1010    const char*   IniFilename;              // = "imgui.ini"        // Path to .ini file. NULL to disable .ini saving.
    1011    const char*   LogFilename;              // = "imgui_log.txt"    // Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
    1012    float         MouseDoubleClickTime;     // = 0.30f              // Time for a double-click, in seconds.
    1013    float         MouseDoubleClickMaxDist;  // = 6.0f               // Distance threshold to stay in to validate a double-click, in pixels.
    1014    float         MouseDragThreshold;       // = 6.0f               // Distance threshold before considering we are dragging.
    1015    int           KeyMap[ImGuiKey_COUNT];   // <unset>              // Map of indices into the KeysDown[512] entries array which represent your "native" keyboard state.
    1016    float         KeyRepeatDelay;           // = 0.250f             // When holding a key/button, time before it starts repeating, in seconds (for buttons in Repeat mode, etc.).
    1017    float         KeyRepeatRate;            // = 0.050f             // When holding a key/button, rate at which it repeats, in seconds.
    1018    void*         UserData;                 // = NULL               // Store your own data for retrieval by callbacks.
    1019 
    1020    ImFontAtlas*  Fonts;                    // <auto>               // Load and assemble one or more fonts into a single tightly packed texture. Output to Fonts array.
    1021    float         FontGlobalScale;          // = 1.0f               // Global scale all fonts
    1022    bool          FontAllowUserScaling;     // = false              // Allow user scaling text of individual window with CTRL+Wheel.
    1023    ImFont*       FontDefault;              // = NULL               // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0].
    1024    ImVec2        DisplayFramebufferScale;  // = (1.0f,1.0f)        // For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui.
    1025    ImVec2        DisplayVisibleMin;        // <unset> (0.0f,0.0f)  // If you use DisplaySize as a virtual space larger than your screen, set DisplayVisibleMin/Max to the visible area.
    1026    ImVec2        DisplayVisibleMax;        // <unset> (0.0f,0.0f)  // If the values are the same, we defaults to Min=(0.0f) and Max=DisplaySize
    1027 
    1028                                            // Advanced/subtle behaviors
    1029    bool          OptMacOSXBehaviors;       // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl
    1030    bool          OptCursorBlink;           // = true               // Enable blinking cursor, for users who consider it annoying.
    1031 
    1032                                            //------------------------------------------------------------------
    1033                                            // Settings (User Functions)
    1034                                            //------------------------------------------------------------------
    1035 
    1036                                            // Optional: access OS clipboard
    1037                                            // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures)
    1038    const char* (*GetClipboardTextFn)(void* user_data);
    1039    void(*SetClipboardTextFn)(void* user_data, const char* text);
    1040    void*       ClipboardUserData;
    1041 
    1042    // Optional: notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME in Windows)
    1043    // (default to use native imm32 api on Windows)
    1044    void(*ImeSetInputScreenPosFn)(int x, int y);
    1045    void*       ImeWindowHandle;            // (Windows) Set this to your HWND to get automatic IME cursor positioning.
    1046 
    1047 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    1048                                            // [OBSOLETE] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now! You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render().
    1049                                            // See example applications if you are unsure of how to implement this.
    1050    void(*RenderDrawListsFn)(ImDrawData* data);
    1051 #endif
    1052 
    1053    //------------------------------------------------------------------
    1054    // Input - Fill before calling NewFrame()
    1055    //------------------------------------------------------------------
    1056 
    1057    ImVec2      MousePos;                       // Mouse position, in pixels. Set to ImVec2(-FLT_MAX,-FLT_MAX) if mouse is unavailable (on another screen, etc.)
    1058    bool        MouseDown[5];                   // Mouse buttons: left, right, middle + extras. ImGui itself mostly only uses left button (BeginPopupContext** are using right button). Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
    1059    float       MouseWheel;                     // Mouse wheel Vertical: 1 unit scrolls about 5 lines text.
    1060    float       MouseWheelH;                    // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends.
    1061    bool        MouseDrawCursor;                // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor).
    1062    bool        KeyCtrl;                        // Keyboard modifier pressed: Control
    1063    bool        KeyShift;                       // Keyboard modifier pressed: Shift
    1064    bool        KeyAlt;                         // Keyboard modifier pressed: Alt
    1065    bool        KeySuper;                       // Keyboard modifier pressed: Cmd/Super/Windows
    1066    bool        KeysDown[512];                  // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys).
    1067    ImWchar     InputCharacters[16 + 1];          // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper.
    1068    float       NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs (keyboard keys will be auto-mapped and be written here by ImGui::NewFrame, all values will be cleared back to zero in ImGui::EndFrame)
    1069 
    1070                                                // Functions
    1071    IMGUI_API void AddInputCharacter(ImWchar c);                        // Add new character into InputCharacters[]
    1072    IMGUI_API void AddInputCharactersUTF8(const char* utf8_chars);      // Add new characters into InputCharacters[] from an UTF-8 string
    1073    inline void    ClearInputCharacters() { InputCharacters[0] = 0; }   // Clear the text input buffer manually
    1074 
    1075                                                                        //------------------------------------------------------------------
    1076                                                                        // Output - Retrieve after calling NewFrame()
    1077                                                                        //------------------------------------------------------------------
    1078 
    1079    bool        WantCaptureMouse;           // When io.WantCaptureMouse is true, imgui will use the mouse inputs, do not dispatch them to your main game/application (in both cases, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.).
    1080    bool        WantCaptureKeyboard;        // When io.WantCaptureKeyboard is true, imgui will use the keyboard inputs, do not dispatch them to your main game/application (in both cases, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.).
    1081    bool        WantTextInput;              // Mobile/console: when io.WantTextInput is true, you may display an on-screen keyboard. This is set by ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active).
    1082    bool        WantSetMousePos;            // MousePos has been altered, back-end should reposition mouse on next frame. Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled.
    1083    bool        NavActive;                  // Directional navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag.
    1084    bool        NavVisible;                 // Directional navigation is visible and allowed (will handle ImGuiKey_NavXXX events).
    1085    float       Framerate;                  // Application framerate estimation, in frame per second. Solely for convenience. Rolling average estimation based on IO.DeltaTime over 120 frames
    1086    int         MetricsRenderVertices;      // Vertices output during last call to Render()
    1087    int         MetricsRenderIndices;       // Indices output during last call to Render() = number of triangles * 3
    1088    int         MetricsActiveWindows;       // Number of visible root windows (exclude child windows)
    1089    ImVec2      MouseDelta;                 // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta.
    1090 
    1091                                            //------------------------------------------------------------------
    1092                                            // [Internal] ImGui will maintain those fields. Forward compatibility not guaranteed!
    1093                                            //------------------------------------------------------------------
    1094 
    1095    ImVec2      MousePosPrev;               // Previous mouse position temporary storage (nb: not for public use, set to MousePos in NewFrame())
    1096    ImVec2      MouseClickedPos[5];         // Position at time of clicking
    1097    float       MouseClickedTime[5];        // Time of last click (used to figure out double-click)
    1098    bool        MouseClicked[5];            // Mouse button went from !Down to Down
    1099    bool        MouseDoubleClicked[5];      // Has mouse button been double-clicked?
    1100    bool        MouseReleased[5];           // Mouse button went from Down to !Down
    1101    bool        MouseDownOwned[5];          // Track if button was clicked inside a window. We don't request mouse capture from the application if click started outside ImGui bounds.
    1102    float       MouseDownDuration[5];       // Duration the mouse button has been down (0.0f == just clicked)
    1103    float       MouseDownDurationPrev[5];   // Previous time the mouse button has been down
    1104    ImVec2      MouseDragMaxDistanceAbs[5]; // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point
    1105    float       MouseDragMaxDistanceSqr[5]; // Squared maximum distance of how much mouse has traveled from the clicking point
    1106    float       KeysDownDuration[512];      // Duration the keyboard key has been down (0.0f == just pressed)
    1107    float       KeysDownDurationPrev[512];  // Previous duration the key has been down
    1108    float       NavInputsDownDuration[ImGuiNavInput_COUNT];
    1109    float       NavInputsDownDurationPrev[ImGuiNavInput_COUNT];
    1110 
    1111    IMGUI_API   ImGuiIO();
     1565    // [OBSOLETE since 1.60+] Rendering function, will be automatically called in Render(). Please call your rendering function yourself now!
     1566    // You can obtain the ImDrawData* by calling ImGui::GetDrawData() after Render(). See example applications if you are unsure of how to implement this.
     1567    void        (*RenderDrawListsFn)(ImDrawData* data);
     1568#else
     1569    // This is only here to keep ImGuiIO the same size/layout, so that IMGUI_DISABLE_OBSOLETE_FUNCTIONS can exceptionally be used outside of imconfig.h.
     1570    void*       RenderDrawListsFnUnused;
     1571#endif
     1572
     1573    //------------------------------------------------------------------
     1574    // Input - Fill before calling NewFrame()
     1575    //------------------------------------------------------------------
     1576
     1577    ImVec2      MousePos;                       // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.)
     1578    bool        MouseDown[5];                   // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Others buttons allows us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
     1579    float       MouseWheel;                     // Mouse wheel Vertical: 1 unit scrolls about 5 lines text.
     1580    float       MouseWheelH;                    // Mouse wheel Horizontal. Most users don't have a mouse with an horizontal wheel, may not be filled by all back-ends.
     1581    bool        KeyCtrl;                        // Keyboard modifier pressed: Control
     1582    bool        KeyShift;                       // Keyboard modifier pressed: Shift
     1583    bool        KeyAlt;                         // Keyboard modifier pressed: Alt
     1584    bool        KeySuper;                       // Keyboard modifier pressed: Cmd/Super/Windows
     1585    bool        KeysDown[512];                  // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys).
     1586    float       NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame().
     1587
     1588    // Functions
     1589    IMGUI_API void  AddInputCharacter(unsigned int c);          // Queue new character input
     1590    IMGUI_API void  AddInputCharacterUTF16(ImWchar16 c);        // Queue new character input from an UTF-16 character, it can be a surrogate
     1591    IMGUI_API void  AddInputCharactersUTF8(const char* str);    // Queue new characters input from an UTF-8 string
     1592    IMGUI_API void  ClearInputCharacters();                     // Clear the text input buffer manually
     1593
     1594    //------------------------------------------------------------------
     1595    // Output - Updated by NewFrame() or EndFrame()/Render()
     1596    // (when reading from the io.WantCaptureMouse, io.WantCaptureKeyboard flags to dispatch your inputs, it is
     1597    //  generally easier and more correct to use their state BEFORE calling NewFrame(). See FAQ for details!)
     1598    //------------------------------------------------------------------
     1599
     1600    bool        WantCaptureMouse;               // Set when Dear ImGui will use mouse inputs, in this case do not dispatch them to your main game/application (either way, always pass on mouse inputs to imgui). (e.g. unclicked mouse is hovering over an imgui window, widget is active, mouse was clicked over an imgui window, etc.).
     1601    bool        WantCaptureKeyboard;            // Set when Dear ImGui will use keyboard inputs, in this case do not dispatch them to your main game/application (either way, always pass keyboard inputs to imgui). (e.g. InputText active, or an imgui window is focused and navigation is enabled, etc.).
     1602    bool        WantTextInput;                  // Mobile/console: when set, you may display an on-screen keyboard. This is set by Dear ImGui when it wants textual keyboard input to happen (e.g. when a InputText widget is active).
     1603    bool        WantSetMousePos;                // MousePos has been altered, back-end should reposition mouse on next frame. Rarely used! Set only when ImGuiConfigFlags_NavEnableSetMousePos flag is enabled.
     1604    bool        WantSaveIniSettings;            // When manual .ini load/save is active (io.IniFilename == NULL), this will be set to notify your application that you can call SaveIniSettingsToMemory() and save yourself. Important: clear io.WantSaveIniSettings yourself after saving!
     1605    bool        NavActive;                      // Keyboard/Gamepad navigation is currently allowed (will handle ImGuiKey_NavXXX events) = a window is focused and it doesn't use the ImGuiWindowFlags_NoNavInputs flag.
     1606    bool        NavVisible;                     // Keyboard/Gamepad navigation is visible and allowed (will handle ImGuiKey_NavXXX events).
     1607    float       Framerate;                      // Application framerate estimate, in frame per second. Solely for convenience. Rolling average estimation based on io.DeltaTime over 120 frames.
     1608    int         MetricsRenderVertices;          // Vertices output during last call to Render()
     1609    int         MetricsRenderIndices;           // Indices output during last call to Render() = number of triangles * 3
     1610    int         MetricsRenderWindows;           // Number of visible windows
     1611    int         MetricsActiveWindows;           // Number of active windows
     1612    int         MetricsActiveAllocations;       // Number of active allocations, updated by MemAlloc/MemFree based on current context. May be off if you have multiple imgui contexts.
     1613    ImVec2      MouseDelta;                     // Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta.
     1614
     1615    //------------------------------------------------------------------
     1616    // [Internal] Dear ImGui will maintain those fields. Forward compatibility not guaranteed!
     1617    //------------------------------------------------------------------
     1618
     1619    ImGuiKeyModFlags KeyMods;                   // Key mods flags (same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags), updated by NewFrame()
     1620    ImVec2      MousePosPrev;                   // Previous mouse position (note that MouseDelta is not necessary == MousePos-MousePosPrev, in case either position is invalid)
     1621    ImVec2      MouseClickedPos[5];             // Position at time of clicking
     1622    double      MouseClickedTime[5];            // Time of last click (used to figure out double-click)
     1623    bool        MouseClicked[5];                // Mouse button went from !Down to Down
     1624    bool        MouseDoubleClicked[5];          // Has mouse button been double-clicked?
     1625    bool        MouseReleased[5];               // Mouse button went from Down to !Down
     1626    bool        MouseDownOwned[5];              // Track if button was clicked inside a dear imgui window. We don't request mouse capture from the application if click started outside ImGui bounds.
     1627    bool        MouseDownWasDoubleClick[5];     // Track if button down was a double-click
     1628    float       MouseDownDuration[5];           // Duration the mouse button has been down (0.0f == just clicked)
     1629    float       MouseDownDurationPrev[5];       // Previous time the mouse button has been down
     1630    ImVec2      MouseDragMaxDistanceAbs[5];     // Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point
     1631    float       MouseDragMaxDistanceSqr[5];     // Squared maximum distance of how much mouse has traveled from the clicking point
     1632    float       KeysDownDuration[512];          // Duration the keyboard key has been down (0.0f == just pressed)
     1633    float       KeysDownDurationPrev[512];      // Previous duration the key has been down
     1634    float       NavInputsDownDuration[ImGuiNavInput_COUNT];
     1635    float       NavInputsDownDurationPrev[ImGuiNavInput_COUNT];
     1636    float       PenPressure;                    // Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui.
     1637    ImWchar16   InputQueueSurrogate;            // For AddInputCharacterUTF16
     1638    ImVector<ImWchar> InputQueueCharacters;     // Queue of _characters_ input (obtained by platform back-end). Fill using AddInputCharacter() helper.
     1639
     1640    IMGUI_API   ImGuiIO();
     1641};
     1642
     1643//-----------------------------------------------------------------------------
     1644// Misc data structures
     1645//-----------------------------------------------------------------------------
     1646
     1647// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used.
     1648// The callback function should return 0 by default.
     1649// Callbacks (follow a flag name and see comments in ImGuiInputTextFlags_ declarations for more details)
     1650// - ImGuiInputTextFlags_CallbackEdit:        Callback on buffer edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
     1651// - ImGuiInputTextFlags_CallbackAlways:      Callback on each iteration
     1652// - ImGuiInputTextFlags_CallbackCompletion:  Callback on pressing TAB
     1653// - ImGuiInputTextFlags_CallbackHistory:     Callback on pressing Up/Down arrows
     1654// - ImGuiInputTextFlags_CallbackCharFilter:  Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
     1655// - ImGuiInputTextFlags_CallbackResize:      Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow.
     1656struct ImGuiInputTextCallbackData
     1657{
     1658    ImGuiInputTextFlags EventFlag;      // One ImGuiInputTextFlags_Callback*    // Read-only
     1659    ImGuiInputTextFlags Flags;          // What user passed to InputText()      // Read-only
     1660    void*               UserData;       // What user passed to InputText()      // Read-only
     1661
     1662    // Arguments for the different callback events
     1663    // - To modify the text buffer in a callback, prefer using the InsertChars() / DeleteChars() function. InsertChars() will take care of calling the resize callback if necessary.
     1664    // - If you know your edits are not going to resize the underlying buffer allocation, you may modify the contents of 'Buf[]' directly. You need to update 'BufTextLen' accordingly (0 <= BufTextLen < BufSize) and set 'BufDirty'' to true so InputText can update its internal state.
     1665    ImWchar             EventChar;      // Character input                      // Read-write   // [CharFilter] Replace character with another one, or set to zero to drop. return 1 is equivalent to setting EventChar=0;
     1666    ImGuiKey            EventKey;       // Key pressed (Up/Down/TAB)            // Read-only    // [Completion,History]
     1667    char*               Buf;            // Text buffer                          // Read-write   // [Resize] Can replace pointer / [Completion,History,Always] Only write to pointed data, don't replace the actual pointer!
     1668    int                 BufTextLen;     // Text length (in bytes)               // Read-write   // [Resize,Completion,History,Always] Exclude zero-terminator storage. In C land: == strlen(some_text), in C++ land: string.length()
     1669    int                 BufSize;        // Buffer size (in bytes) = capacity+1  // Read-only    // [Resize,Completion,History,Always] Include zero-terminator storage. In C land == ARRAYSIZE(my_char_array), in C++ land: string.capacity()+1
     1670    bool                BufDirty;       // Set if you modify Buf/BufTextLen!    // Write        // [Completion,History,Always]
     1671    int                 CursorPos;      //                                      // Read-write   // [Completion,History,Always]
     1672    int                 SelectionStart; //                                      // Read-write   // [Completion,History,Always] == to SelectionEnd when no selection)
     1673    int                 SelectionEnd;   //                                      // Read-write   // [Completion,History,Always]
     1674
     1675    // Helper functions for text manipulation.
     1676    // Use those function to benefit from the CallbackResize behaviors. Calling those function reset the selection.
     1677    IMGUI_API ImGuiInputTextCallbackData();
     1678    IMGUI_API void      DeleteChars(int pos, int bytes_count);
     1679    IMGUI_API void      InsertChars(int pos, const char* text, const char* text_end = NULL);
     1680    void                SelectAll()             { SelectionStart = 0; SelectionEnd = BufTextLen; }
     1681    void                ClearSelection()        { SelectionStart = SelectionEnd = BufTextLen; }
     1682    bool                HasSelection() const    { return SelectionStart != SelectionEnd; }
     1683};
     1684
     1685// Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin().
     1686// NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough.
     1687struct ImGuiSizeCallbackData
     1688{
     1689    void*   UserData;       // Read-only.   What user passed to SetNextWindowSizeConstraints()
     1690    ImVec2  Pos;            // Read-only.   Window position, for reference.
     1691    ImVec2  CurrentSize;    // Read-only.   Current window size.
     1692    ImVec2  DesiredSize;    // Read-write.  Desired size, based on user's mouse position. Write to this field to restrain resizing.
     1693};
     1694
     1695// Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload()
     1696struct ImGuiPayload
     1697{
     1698    // Members
     1699    void*           Data;               // Data (copied and owned by dear imgui)
     1700    int             DataSize;           // Data size
     1701
     1702    // [Internal]
     1703    ImGuiID         SourceId;           // Source item id
     1704    ImGuiID         SourceParentId;     // Source parent id (if available)
     1705    int             DataFrameCount;     // Data timestamp
     1706    char            DataType[32 + 1];   // Data type tag (short user-supplied string, 32 characters max)
     1707    bool            Preview;            // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets)
     1708    bool            Delivery;           // Set when AcceptDragDropPayload() was called and mouse button is released over the target item.
     1709
     1710    ImGuiPayload()  { Clear(); }
     1711    void Clear()    { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; }
     1712    bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; }
     1713    bool IsPreview() const                  { return Preview; }
     1714    bool IsDelivery() const                 { return Delivery; }
    11121715};
    11131716
    11141717//-----------------------------------------------------------------------------
    11151718// Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details)
     1719// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead.
    11161720//-----------------------------------------------------------------------------
    11171721
     
    11191723namespace ImGui
    11201724{
    1121    // OBSOLETED in 1.61 (from Apr 2018)
    1122    bool                InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'!
    1123    bool                InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags = 0);
    1124    bool                InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags = 0);
    1125    bool                InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags = 0);
    1126    // OBSOLETED in 1.60 (from Dec 2017)
    1127    static inline bool  IsAnyWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); }
    1128    static inline bool  IsAnyWindowHovered() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }
    1129    static inline ImVec2 CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge = false, float outward = 0.f) { (void)on_edge; (void)outward; IM_ASSERT(0); return pos; }
    1130    // OBSOLETED in 1.53 (between Oct 2017 and Dec 2017)
    1131    static inline void  ShowTestWindow() { return ShowDemoWindow(); }
    1132    static inline bool  IsRootWindowFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootWindow); }
    1133    static inline bool  IsRootWindowOrAnyChildFocused() { return IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows); }
    1134    static inline void  SetNextWindowContentWidth(float w) { SetNextWindowContentSize(ImVec2(w, 0.0f)); }
    1135    static inline float GetItemsLineHeightWithSpacing() { return GetFrameHeightWithSpacing(); }
    1136    // OBSOLETED in 1.52 (between Aug 2017 and Oct 2017)
    1137    bool                Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha_override = -1.0f, ImGuiWindowFlags flags = 0); // Use SetNextWindowSize(size, ImGuiCond_FirstUseEver) + SetNextWindowBgAlpha() instead.
    1138    static inline bool  IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); }
    1139    static inline void  AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); }
    1140    static inline void  SetNextWindowPosCenter(ImGuiCond c = 0) { ImGuiIO& io = GetIO(); SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), c, ImVec2(0.5f, 0.5f)); }
    1141    // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017)
    1142    static inline bool  IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); }
    1143    static inline bool  IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // This was misleading and partly broken. You probably want to use the ImGui::GetIO().WantCaptureMouse flag instead.
    1144    static inline bool  IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }
    1145    static inline bool  IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); }
    1146    // OBSOLETED IN 1.49 (between Apr 2016 and May 2016)
    1147    static inline bool  CollapsingHeader(const char* label, const char* str_id, bool framed = true, bool default_open = false) { (void)str_id; (void)framed; ImGuiTreeNodeFlags default_open_flags = 1 << 5; return CollapsingHeader(label, (default_open ? default_open_flags : 0)); }
     1725    // OBSOLETED in 1.79 (from August 2020)
     1726    static inline void  OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry!
     1727    // OBSOLETED in 1.78 (from June 2020)
     1728    // Old drag/sliders functions that took a 'float power = 1.0' argument instead of flags.
     1729    // For shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
     1730    IMGUI_API bool      DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power);
     1731    IMGUI_API bool      DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power);
     1732    static inline bool  DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* format, float power)    { return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, power); }
     1733    static inline bool  DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, power); }
     1734    static inline bool  DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); }
     1735    static inline bool  DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* format, float power) { return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, power); }
     1736    IMGUI_API bool      SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power);
     1737    IMGUI_API bool      SliderScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, const void* p_min, const void* p_max, const char* format, float power);
     1738    static inline bool  SliderFloat(const char* label, float* v, float v_min, float v_max, const char* format, float power)                 { return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, power); }
     1739    static inline bool  SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* format, float power)              { return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, power); }
     1740    static inline bool  SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* format, float power)              { return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, power); }
     1741    static inline bool  SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* format, float power)              { return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, power); }
     1742    // OBSOLETED in 1.77 (from June 2020)
     1743    static inline bool  BeginPopupContextWindow(const char* str_id, ImGuiMouseButton mb, bool over_items) { return BeginPopupContextWindow(str_id, mb | (over_items ? 0 : ImGuiPopupFlags_NoOpenOverItems)); }
     1744    // OBSOLETED in 1.72 (from April 2019)
     1745    static inline void  TreeAdvanceToLabelPos()               { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); }
     1746    // OBSOLETED in 1.71 (from June 2019)
     1747    static inline void  SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); }
     1748    // OBSOLETED in 1.70 (from May 2019)
     1749    static inline float GetContentRegionAvailWidth()          { return GetContentRegionAvail().x; }
     1750    // OBSOLETED in 1.69 (from Mar 2019)
     1751    static inline ImDrawList* GetOverlayDrawList()            { return GetForegroundDrawList(); }
     1752    // OBSOLETED in 1.66 (from Sep 2018)
     1753    static inline void  SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); }
     1754    // OBSOLETED in 1.63 (between Aug 2018 and Sept 2018)
     1755    static inline bool  IsItemDeactivatedAfterChange()        { return IsItemDeactivatedAfterEdit(); }
     1756    // OBSOLETED in 1.61 (between Apr 2018 and Aug 2018)
     1757    IMGUI_API bool      InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags flags = 0); // Use the 'const char* format' version instead of 'decimal_precision'!
     1758    IMGUI_API bool      InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags flags = 0);
     1759    IMGUI_API bool      InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags flags = 0);
     1760    IMGUI_API bool      InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags flags = 0);
     1761    // OBSOLETED in 1.60 (between Dec 2017 and Apr 2018)
     1762    static inline bool  IsAnyWindowFocused()                  { return IsWindowFocused(ImGuiFocusedFlags_AnyWindow); }
     1763    static inline bool  IsAnyWindowHovered()                  { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }
    11481764}
     1765typedef ImGuiInputTextCallback      ImGuiTextEditCallback;    // OBSOLETED in 1.63 (from Aug 2018): made the names consistent
     1766typedef ImGuiInputTextCallbackData  ImGuiTextEditCallbackData;
    11491767#endif
    11501768
     
    11531771//-----------------------------------------------------------------------------
    11541772
    1155 // Helper: Lightweight std::vector<> like class to avoid dragging dependencies (also: Windows implementation of STL with debug enabled is absurdly slow, so let's bypass it so our code runs fast in debug).
    1156 // *Important* Our implementation does NOT call C++ constructors/destructors. This is intentional, we do not require it but you have to be mindful of that. Do not use this class as a straight std::vector replacement in your code!
    1157 template<typename T>
    1158 class ImVector
    1159 {
    1160 public:
    1161    int                         Size;
    1162    int                         Capacity;
    1163    T*                          Data;
    1164 
    1165    typedef T                   value_type;
    1166    typedef value_type*         iterator;
    1167    typedef const value_type*   const_iterator;
    1168 
    1169    inline ImVector() { Size = Capacity = 0; Data = NULL; }
    1170    inline ~ImVector() { if (Data) ImGui::MemFree(Data); }
    1171    inline ImVector(const ImVector<T>& src) { Size = Capacity = 0; Data = NULL; operator=(src); }
    1172    inline ImVector& operator=(const ImVector<T>& src) { clear(); resize(src.Size); memcpy(Data, src.Data, (size_t)Size * sizeof(value_type)); return *this; }
    1173 
    1174    inline bool                 empty() const { return Size == 0; }
    1175    inline int                  size() const { return Size; }
    1176    inline int                  capacity() const { return Capacity; }
    1177    inline value_type&          operator[](int i) { IM_ASSERT(i < Size); return Data[i]; }
    1178    inline const value_type&    operator[](int i) const { IM_ASSERT(i < Size); return Data[i]; }
    1179 
    1180    inline void                 clear() { if (Data) { Size = Capacity = 0; ImGui::MemFree(Data); Data = NULL; } }
    1181    inline iterator             begin() { return Data; }
    1182    inline const_iterator       begin() const { return Data; }
    1183    inline iterator             end() { return Data + Size; }
    1184    inline const_iterator       end() const { return Data + Size; }
    1185    inline value_type&          front() { IM_ASSERT(Size > 0); return Data[0]; }
    1186    inline const value_type&    front() const { IM_ASSERT(Size > 0); return Data[0]; }
    1187    inline value_type&          back() { IM_ASSERT(Size > 0); return Data[Size - 1]; }
    1188    inline const value_type&    back() const { IM_ASSERT(Size > 0); return Data[Size - 1]; }
    1189    inline void                 swap(ImVector<value_type>& rhs) { int rhs_size = rhs.Size; rhs.Size = Size; Size = rhs_size; int rhs_cap = rhs.Capacity; rhs.Capacity = Capacity; Capacity = rhs_cap; value_type* rhs_data = rhs.Data; rhs.Data = Data; Data = rhs_data; }
    1190 
    1191    inline int          _grow_capacity(int sz) const { int new_capacity = Capacity ? (Capacity + Capacity / 2) : 8; return new_capacity > sz ? new_capacity : sz; }
    1192    inline void         resize(int new_size) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); Size = new_size; }
    1193    inline void         resize(int new_size, const value_type& v) { if (new_size > Capacity) reserve(_grow_capacity(new_size)); if (new_size > Size) for (int n = Size; n < new_size; n++) memcpy(&Data[n], &v, sizeof(v)); Size = new_size; }
    1194    inline void         reserve(int new_capacity)
    1195    {
    1196       if (new_capacity <= Capacity)
    1197          return;
    1198       value_type* new_data = (value_type*)ImGui::MemAlloc((size_t)new_capacity * sizeof(value_type));
    1199       if (Data)
    1200          memcpy(new_data, Data, (size_t)Size * sizeof(value_type));
    1201       ImGui::MemFree(Data);
    1202       Data = new_data;
    1203       Capacity = new_capacity;
    1204    }
    1205 
    1206    // NB: &v cannot be pointing inside the ImVector Data itself! e.g. v.push_back(v[10]) is forbidden.
    1207    inline void         push_back(const value_type& v) { if (Size == Capacity) reserve(_grow_capacity(Size + 1)); memcpy(&Data[Size], &v, sizeof(v)); Size++; }
    1208    inline void         pop_back() { IM_ASSERT(Size > 0); Size--; }
    1209    inline void         push_front(const value_type& v) { if (Size == 0) push_back(v); else insert(Data, v); }
    1210    inline iterator     erase(const_iterator it) { IM_ASSERT(it >= Data && it < Data + Size); const ptrdiff_t off = it - Data; memmove(Data + off, Data + off + 1, ((size_t)Size - (size_t)off - 1) * sizeof(value_type)); Size--; return Data + off; }
    1211    inline iterator     insert(const_iterator it, const value_type& v) { IM_ASSERT(it >= Data && it <= Data + Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(value_type)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; }
    1212    inline bool         contains(const value_type& v) const { const T* data = Data;  const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }
    1213 };
    1214 
    1215 // Helper: IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE() macros to call MemAlloc + Placement New, Placement Delete + MemFree
    1216 // We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
    1217 // Defining a custom placement new() with a dummy parameter allows us to bypass including <new> which on some platforms complains when user has disabled exceptions.
    1218 struct ImNewDummy {};
    1219 inline void* operator new(size_t, ImNewDummy, void* ptr) { return ptr; }
    1220 inline void  operator delete(void*, ImNewDummy, void*) {} // This is only required so we can use the symetrical new()
    1221 #define IM_PLACEMENT_NEW(_PTR)              new(ImNewDummy(), _PTR)
    1222 #define IM_NEW(_TYPE)                       new(ImNewDummy(), ImGui::MemAlloc(sizeof(_TYPE))) _TYPE
    1223 template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
     1773// Helper: Unicode defines
     1774#define IM_UNICODE_CODEPOINT_INVALID 0xFFFD     // Invalid Unicode code point (standard value).
     1775#ifdef IMGUI_USE_WCHAR32
     1776#define IM_UNICODE_CODEPOINT_MAX     0x10FFFF   // Maximum Unicode code point supported by this build.
     1777#else
     1778#define IM_UNICODE_CODEPOINT_MAX     0xFFFF     // Maximum Unicode code point supported by this build.
     1779#endif
    12241780
    12251781// Helper: Execute a block of code at maximum once a frame. Convenient if you want to quickly create an UI within deep-nested code that runs multiple times every frame.
     
    12271783struct ImGuiOnceUponAFrame
    12281784{
    1229    ImGuiOnceUponAFrame() { RefFrame = -1; }
    1230    mutable int RefFrame;
    1231    operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; }
    1232 };
    1233 
    1234 // Helper: Macro for ImGuiOnceUponAFrame. Attention: The macro expands into 2 statement so make sure you don't use it within e.g. an if() statement without curly braces.
    1235 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS    // Will obsolete
    1236 #define IMGUI_ONCE_UPON_A_FRAME     static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf)
    1237 #endif
     1785    ImGuiOnceUponAFrame() { RefFrame = -1; }
     1786    mutable int RefFrame;
     1787    operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; }
     1788};
    12381789
    12391790// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
    12401791struct ImGuiTextFilter
    12411792{
    1242    struct TextRange
    1243    {
    1244       const char* b;
    1245       const char* e;
    1246 
    1247       TextRange() { b = e = NULL; }
    1248       TextRange(const char* _b, const char* _e) { b = _b; e = _e; }
    1249       const char* begin() const { return b; }
    1250       const char* end() const { return e; }
    1251       bool empty() const { return b == e; }
    1252       char front() const { return *b; }
    1253       static bool is_blank(char c) { return c == ' ' || c == '\t'; }
    1254       void trim_blanks() { while (b < e && is_blank(*b)) b++; while (e > b && is_blank(*(e - 1))) e--; }
    1255       IMGUI_API void split(char separator, ImVector<TextRange>& out);
    1256    };
    1257 
    1258    char                InputBuf[256];
    1259    ImVector<TextRange> Filters;
    1260    int                 CountGrep;
    1261 
    1262    IMGUI_API           ImGuiTextFilter(const char* default_filter = "");
    1263    IMGUI_API bool      Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f);    // Helper calling InputText+Build
    1264    IMGUI_API bool      PassFilter(const char* text, const char* text_end = NULL) const;
    1265    IMGUI_API void      Build();
    1266    void                Clear() { InputBuf[0] = 0; Build(); }
    1267    bool                IsActive() const { return !Filters.empty(); }
    1268 };
    1269 
    1270 // Helper: Text buffer for logging/accumulating text
     1793    IMGUI_API           ImGuiTextFilter(const char* default_filter = "");
     1794    IMGUI_API bool      Draw(const char* label = "Filter (inc,-exc)", float width = 0.0f);  // Helper calling InputText+Build
     1795    IMGUI_API bool      PassFilter(const char* text, const char* text_end = NULL) const;
     1796    IMGUI_API void      Build();
     1797    void                Clear()          { InputBuf[0] = 0; Build(); }
     1798    bool                IsActive() const { return !Filters.empty(); }
     1799
     1800    // [Internal]
     1801    struct ImGuiTextRange
     1802    {
     1803        const char*     b;
     1804        const char*     e;
     1805
     1806        ImGuiTextRange()                                { b = e = NULL; }
     1807        ImGuiTextRange(const char* _b, const char* _e)  { b = _b; e = _e; }
     1808        bool            empty() const                   { return b == e; }
     1809        IMGUI_API void  split(char separator, ImVector<ImGuiTextRange>* out) const;
     1810    };
     1811    char                    InputBuf[256];
     1812    ImVector<ImGuiTextRange>Filters;
     1813    int                     CountGrep;
     1814};
     1815
     1816// Helper: Growable text buffer for logging/accumulating text
     1817// (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder')
    12711818struct ImGuiTextBuffer
    12721819{
    1273    ImVector<char>      Buf;
    1274 
    1275    ImGuiTextBuffer() { Buf.push_back(0); }
    1276    inline char         operator[](int i) { return Buf.Data[i]; }
    1277    const char*         begin() const { return &Buf.front(); }
    1278    const char*         end() const { return &Buf.back(); }      // Buf is zero-terminated, so end() will point on the zero-terminator
    1279    int                 size() const { return Buf.Size - 1; }
    1280    bool                empty() { return Buf.Size <= 1; }
    1281    void                clear() { Buf.clear(); Buf.push_back(0); }
    1282    void                reserve(int capacity) { Buf.reserve(capacity); }
    1283    const char*         c_str() const { return Buf.Data; }
    1284    IMGUI_API void      appendf(const char* fmt, ...) IM_FMTARGS(2);
    1285    IMGUI_API void      appendfv(const char* fmt, va_list args) IM_FMTLIST(2);
    1286 };
    1287 
    1288 // Helper: Simple Key->value storage
     1820    ImVector<char>      Buf;
     1821    IMGUI_API static char EmptyString[1];
     1822
     1823    ImGuiTextBuffer()   { }
     1824    inline char         operator[](int i) const { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }
     1825    const char*         begin() const           { return Buf.Data ? &Buf.front() : EmptyString; }
     1826    const char*         end() const             { return Buf.Data ? &Buf.back() : EmptyString; }   // Buf is zero-terminated, so end() will point on the zero-terminator
     1827    int                 size() const            { return Buf.Size ? Buf.Size - 1 : 0; }
     1828    bool                empty() const           { return Buf.Size <= 1; }
     1829    void                clear()                 { Buf.clear(); }
     1830    void                reserve(int capacity)   { Buf.reserve(capacity); }
     1831    const char*         c_str() const           { return Buf.Data ? Buf.Data : EmptyString; }
     1832    IMGUI_API void      append(const char* str, const char* str_end = NULL);
     1833    IMGUI_API void      appendf(const char* fmt, ...) IM_FMTARGS(2);
     1834    IMGUI_API void      appendfv(const char* fmt, va_list args) IM_FMTLIST(2);
     1835};
     1836
     1837// Helper: Key->Value storage
    12891838// Typically you don't have to worry about this since a storage is held within each Window.
    12901839// We use it to e.g. store collapse state for a tree (Int 0/1)
     
    12961845struct ImGuiStorage
    12971846{
    1298    struct Pair
    1299    {
    1300       ImGuiID key;
    1301       union { int val_i; float val_f; void* val_p; };
    1302       Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; }
    1303       Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; }
    1304       Pair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; }
    1305    };
    1306    ImVector<Pair>      Data;
    1307 
    1308    // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N)
    1309    // - Set***() functions find pair, insertion on demand if missing.
    1310    // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair.
    1311    void                Clear() { Data.clear(); }
    1312    IMGUI_API int       GetInt(ImGuiID key, int default_val = 0) const;
    1313    IMGUI_API void      SetInt(ImGuiID key, int val);
    1314    IMGUI_API bool      GetBool(ImGuiID key, bool default_val = false) const;
    1315    IMGUI_API void      SetBool(ImGuiID key, bool val);
    1316    IMGUI_API float     GetFloat(ImGuiID key, float default_val = 0.0f) const;
    1317    IMGUI_API void      SetFloat(ImGuiID key, float val);
    1318    IMGUI_API void*     GetVoidPtr(ImGuiID key) const; // default_val is NULL
    1319    IMGUI_API void      SetVoidPtr(ImGuiID key, void* val);
    1320 
    1321    // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set.
    1322    // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
    1323    // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct)
    1324    //      float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar;
    1325    IMGUI_API int*      GetIntRef(ImGuiID key, int default_val = 0);
    1326    IMGUI_API bool*     GetBoolRef(ImGuiID key, bool default_val = false);
    1327    IMGUI_API float*    GetFloatRef(ImGuiID key, float default_val = 0.0f);
    1328    IMGUI_API void**    GetVoidPtrRef(ImGuiID key, void* default_val = NULL);
    1329 
    1330    // Use on your own storage if you know only integer are being stored (open/close all tree nodes)
    1331    IMGUI_API void      SetAllInt(int val);
    1332 
    1333    // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
    1334    IMGUI_API void      BuildSortByKey();
    1335 };
    1336 
    1337 // Shared state of InputText(), passed to callback when a ImGuiInputTextFlags_Callback* flag is used and the corresponding callback is triggered.
    1338 struct ImGuiTextEditCallbackData
    1339 {
    1340    ImGuiInputTextFlags EventFlag;      // One of ImGuiInputTextFlags_Callback* // Read-only
    1341    ImGuiInputTextFlags Flags;          // What user passed to InputText()      // Read-only
    1342    void*               UserData;       // What user passed to InputText()      // Read-only
    1343    bool                ReadOnly;       // Read-only mode                       // Read-only
    1344 
    1345                                        // CharFilter event:
    1346    ImWchar             EventChar;      // Character input                      // Read-write (replace character or set to zero)
    1347 
    1348                                        // Completion,History,Always events:
    1349                                        // If you modify the buffer contents make sure you update 'BufTextLen' and set 'BufDirty' to true.
    1350    ImGuiKey            EventKey;       // Key pressed (Up/Down/TAB)            // Read-only
    1351    char*               Buf;            // Current text buffer                  // Read-write (pointed data only, can't replace the actual pointer)
    1352    int                 BufTextLen;     // Current text length in bytes         // Read-write
    1353    int                 BufSize;        // Maximum text length in bytes         // Read-only
    1354    bool                BufDirty;       // Set if you modify Buf/BufTextLen!!   // Write
    1355    int                 CursorPos;      //                                      // Read-write
    1356    int                 SelectionStart; //                                      // Read-write (== to SelectionEnd when no selection)
    1357    int                 SelectionEnd;   //                                      // Read-write
    1358 
    1359                                        // NB: Helper functions for text manipulation. Calling those function loses selection.
    1360    IMGUI_API void    DeleteChars(int pos, int bytes_count);
    1361    IMGUI_API void    InsertChars(int pos, const char* text, const char* text_end = NULL);
    1362    bool              HasSelection() const { return SelectionStart != SelectionEnd; }
    1363 };
    1364 
    1365 // Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin().
    1366 // NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough.
    1367 struct ImGuiSizeCallbackData
    1368 {
    1369    void*   UserData;       // Read-only.   What user passed to SetNextWindowSizeConstraints()
    1370    ImVec2  Pos;            // Read-only.   Window position, for reference.
    1371    ImVec2  CurrentSize;    // Read-only.   Current window size.
    1372    ImVec2  DesiredSize;    // Read-write.  Desired size, based on user's mouse position. Write to this field to restrain resizing.
    1373 };
    1374 
    1375 // Data payload for Drag and Drop operations
    1376 struct ImGuiPayload
    1377 {
    1378    // Members
    1379    void*           Data;               // Data (copied and owned by dear imgui)
    1380    int             DataSize;           // Data size
    1381 
    1382                                        // [Internal]
    1383    ImGuiID         SourceId;           // Source item id
    1384    ImGuiID         SourceParentId;     // Source parent id (if available)
    1385    int             DataFrameCount;     // Data timestamp
    1386    char            DataType[32 + 1];     // Data type tag (short user-supplied string, 32 characters max)
    1387    bool            Preview;            // Set when AcceptDragDropPayload() was called and mouse has been hovering the target item (nb: handle overlapping drag targets)
    1388    bool            Delivery;           // Set when AcceptDragDropPayload() was called and mouse button is released over the target item.
    1389 
    1390    ImGuiPayload() { Clear(); }
    1391    void Clear() { SourceId = SourceParentId = 0; Data = NULL; DataSize = 0; memset(DataType, 0, sizeof(DataType)); DataFrameCount = -1; Preview = Delivery = false; }
    1392    bool IsDataType(const char* type) const { return DataFrameCount != -1 && strcmp(type, DataType) == 0; }
    1393    bool IsPreview() const { return Preview; }
    1394    bool IsDelivery() const { return Delivery; }
    1395 };
    1396 
    1397 // Helpers macros to generate 32-bits encoded colors
     1847    // [Internal]
     1848    struct ImGuiStoragePair
     1849    {
     1850        ImGuiID key;
     1851        union { int val_i; float val_f; void* val_p; };
     1852        ImGuiStoragePair(ImGuiID _key, int _val_i)      { key = _key; val_i = _val_i; }
     1853        ImGuiStoragePair(ImGuiID _key, float _val_f)    { key = _key; val_f = _val_f; }
     1854        ImGuiStoragePair(ImGuiID _key, void* _val_p)    { key = _key; val_p = _val_p; }
     1855    };
     1856
     1857    ImVector<ImGuiStoragePair>      Data;
     1858
     1859    // - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N)
     1860    // - Set***() functions find pair, insertion on demand if missing.
     1861    // - Sorted insertion is costly, paid once. A typical frame shouldn't need to insert any new pair.
     1862    void                Clear() { Data.clear(); }
     1863    IMGUI_API int       GetInt(ImGuiID key, int default_val = 0) const;
     1864    IMGUI_API void      SetInt(ImGuiID key, int val);
     1865    IMGUI_API bool      GetBool(ImGuiID key, bool default_val = false) const;
     1866    IMGUI_API void      SetBool(ImGuiID key, bool val);
     1867    IMGUI_API float     GetFloat(ImGuiID key, float default_val = 0.0f) const;
     1868    IMGUI_API void      SetFloat(ImGuiID key, float val);
     1869    IMGUI_API void*     GetVoidPtr(ImGuiID key) const; // default_val is NULL
     1870    IMGUI_API void      SetVoidPtr(ImGuiID key, void* val);
     1871
     1872    // - Get***Ref() functions finds pair, insert on demand if missing, return pointer. Useful if you intend to do Get+Set.
     1873    // - References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
     1874    // - A typical use case where this is convenient for quick hacking (e.g. add storage during a live Edit&Continue session if you can't modify existing struct)
     1875    //      float* pvar = ImGui::GetFloatRef(key); ImGui::SliderFloat("var", pvar, 0, 100.0f); some_var += *pvar;
     1876    IMGUI_API int*      GetIntRef(ImGuiID key, int default_val = 0);
     1877    IMGUI_API bool*     GetBoolRef(ImGuiID key, bool default_val = false);
     1878    IMGUI_API float*    GetFloatRef(ImGuiID key, float default_val = 0.0f);
     1879    IMGUI_API void**    GetVoidPtrRef(ImGuiID key, void* default_val = NULL);
     1880
     1881    // Use on your own storage if you know only integer are being stored (open/close all tree nodes)
     1882    IMGUI_API void      SetAllInt(int val);
     1883
     1884    // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
     1885    IMGUI_API void      BuildSortByKey();
     1886};
     1887
     1888// Helper: Manually clip large list of items.
     1889// If you are submitting lots of evenly spaced items and you have a random access to the list, you can perform coarse
     1890// clipping based on visibility to save yourself from processing those items at all.
     1891// The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped.
     1892// (Dear ImGui already clip items based on their bounds but it needs to measure text size to do so, whereas manual coarse clipping before submission makes this cost and your own data fetching/submission cost almost null)
     1893// Usage:
     1894//   ImGuiListClipper clipper;
     1895//   clipper.Begin(1000);         // We have 1000 elements, evenly spaced.
     1896//   while (clipper.Step())
     1897//       for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
     1898//           ImGui::Text("line number %d", i);
     1899// Generally what happens is:
     1900// - Clipper lets you process the first element (DisplayStart = 0, DisplayEnd = 1) regardless of it being visible or not.
     1901// - User code submit one element.
     1902// - Clipper can measure the height of the first element
     1903// - Clipper calculate the actual range of elements to display based on the current clipping rectangle, position the cursor before the first visible element.
     1904// - User code submit visible elements.
     1905struct ImGuiListClipper
     1906{
     1907    int     DisplayStart;
     1908    int     DisplayEnd;
     1909
     1910    // [Internal]
     1911    int     ItemsCount;
     1912    int     StepNo;
     1913    float   ItemsHeight;
     1914    float   StartPosY;
     1915
     1916    IMGUI_API ImGuiListClipper();
     1917    IMGUI_API ~ImGuiListClipper();
     1918
     1919    // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step)
     1920    // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing().
     1921    IMGUI_API void Begin(int items_count, float items_height = -1.0f);  // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1.
     1922    IMGUI_API void End();                                               // Automatically called on the last call of Step() that returns false.
     1923    IMGUI_API bool Step();                                              // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items.
     1924
     1925#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     1926    inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79]
     1927#endif
     1928};
     1929
     1930// Helpers macros to generate 32-bit encoded colors
    13981931#ifdef IMGUI_USE_BGRA_PACKED_COLOR
    13991932#define IM_COL32_R_SHIFT    16
     
    14141947#define IM_COL32_BLACK_TRANS IM_COL32(0,0,0,0)          // Transparent black = 0x00000000
    14151948
    1416 // Helper: ImColor() implicity converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float)
     1949// Helper: ImColor() implicitly converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float)
    14171950// Prefer using IM_COL32() macros if you want a guaranteed compile-time ImU32 for usage with ImDrawList API.
    14181951// **Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class. MAY OBSOLETE.
     
    14201953struct ImColor
    14211954{
    1422    ImVec4              Value;
    1423 
    1424    ImColor() { Value.x = Value.y = Value.z = Value.w = 0.0f; }
    1425    ImColor(int r, int g, int b, int a = 255) { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; }
    1426    ImColor(ImU32 rgba) { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; }
    1427    ImColor(float r, float g, float b, float a = 1.0f) { Value.x = r; Value.y = g; Value.z = b; Value.w = a; }
    1428    ImColor(const ImVec4& col) { Value = col; }
    1429    inline operator ImU32() const { return ImGui::ColorConvertFloat4ToU32(Value); }
    1430    inline operator ImVec4() const { return Value; }
    1431 
    1432    // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers.
    1433    inline void    SetHSV(float h, float s, float v, float a = 1.0f) { ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; }
    1434    static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); }
    1435 };
    1436 
    1437 // Helper: Manually clip large list of items.
    1438 // If you are submitting lots of evenly spaced items and you have a random access to the list, you can perform coarse clipping based on visibility to save yourself from processing those items at all.
    1439 // The clipper calculates the range of visible items and advance the cursor to compensate for the non-visible items we have skipped.
    1440 // ImGui already clip items based on their bounds but it needs to measure text size to do so. Coarse clipping before submission makes this cost and your own data fetching/submission cost null.
    1441 // Usage:
    1442 //     ImGuiListClipper clipper(1000);  // we have 1000 elements, evenly spaced.
    1443 //     while (clipper.Step())
    1444 //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
    1445 //             ImGui::Text("line number %d", i);
    1446 // - Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height (step skipped if we passed a known height as second arg to constructor).
    1447 // - 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.
    1448 // - (Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user call Step(). Does nothing and switch to Step 3.)
    1449 // - 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.
    1450 struct ImGuiListClipper
    1451 {
    1452    float   StartPosY;
    1453    float   ItemsHeight;
    1454    int     ItemsCount, StepNo, DisplayStart, DisplayEnd;
    1455 
    1456    // items_count:  Use -1 to ignore (you can call Begin later). Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step).
    1457    // items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing().
    1458    // If you don't specify an items_height, you NEED to call Step(). If you specify items_height you may call the old Begin()/End() api directly, but prefer calling Step().
    1459    ImGuiListClipper(int items_count = -1, float items_height = -1.0f) { Begin(items_count, items_height); } // NB: Begin() initialize every fields (as we allow user to call Begin/End multiple times on a same instance if they want).
    1460    ~ImGuiListClipper() { IM_ASSERT(ItemsCount == -1); }      // Assert if user forgot to call End() or Step() until false.
    1461 
    1462    IMGUI_API bool Step();                                              // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items.
    1463    IMGUI_API void Begin(int items_count, float items_height = -1.0f);  // Automatically called by constructor if you passed 'items_count' or by Step() in Step 1.
    1464    IMGUI_API void End();                                               // Automatically called on the last call of Step() that returns false.
    1465 };
    1466 
    1467 //-----------------------------------------------------------------------------
    1468 // Draw List
     1955    ImVec4              Value;
     1956
     1957    ImColor()                                                       { Value.x = Value.y = Value.z = Value.w = 0.0f; }
     1958    ImColor(int r, int g, int b, int a = 255)                       { float sc = 1.0f / 255.0f; Value.x = (float)r * sc; Value.y = (float)g * sc; Value.z = (float)b * sc; Value.w = (float)a * sc; }
     1959    ImColor(ImU32 rgba)                                             { float sc = 1.0f / 255.0f; Value.x = (float)((rgba >> IM_COL32_R_SHIFT) & 0xFF) * sc; Value.y = (float)((rgba >> IM_COL32_G_SHIFT) & 0xFF) * sc; Value.z = (float)((rgba >> IM_COL32_B_SHIFT) & 0xFF) * sc; Value.w = (float)((rgba >> IM_COL32_A_SHIFT) & 0xFF) * sc; }
     1960    ImColor(float r, float g, float b, float a = 1.0f)              { Value.x = r; Value.y = g; Value.z = b; Value.w = a; }
     1961    ImColor(const ImVec4& col)                                      { Value = col; }
     1962    inline operator ImU32() const                                   { return ImGui::ColorConvertFloat4ToU32(Value); }
     1963    inline operator ImVec4() const                                  { return Value; }
     1964
     1965    // FIXME-OBSOLETE: May need to obsolete/cleanup those helpers.
     1966    inline void    SetHSV(float h, float s, float v, float a = 1.0f){ ImGui::ColorConvertHSVtoRGB(h, s, v, Value.x, Value.y, Value.z); Value.w = a; }
     1967    static ImColor HSV(float h, float s, float v, float a = 1.0f)   { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); }
     1968};
     1969
     1970//-----------------------------------------------------------------------------
     1971// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
    14691972// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList.
    14701973//-----------------------------------------------------------------------------
    14711974
    1472 // Draw callbacks for advanced uses.
    1473 // NB- You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering (you can poke into the draw list for that)
    1474 // Draw callback may be useful for example, A) Change your GPU render state, B) render a complex 3D scene inside a UI element (without an intermediate texture/render target), etc.
    1475 // The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) cmd.UserCallback(parent_list, cmd); else RenderTriangles()'
    1476 typedef void(*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd);
     1975// The maximum line width to bake anti-aliased textures for. Build atlas with ImFontAtlasFlags_NoBakedLines to disable baking.
     1976#ifndef IM_DRAWLIST_TEX_LINES_WIDTH_MAX
     1977#define IM_DRAWLIST_TEX_LINES_WIDTH_MAX     (63)
     1978#endif
     1979
     1980// ImDrawCallback: Draw callbacks for advanced uses [configurable type: override in imconfig.h]
     1981// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering,
     1982// you can poke into the draw list for that! Draw callback may be useful for example to:
     1983//  A) Change your GPU render state,
     1984//  B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc.
     1985// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }'
     1986// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering back-end accordingly.
     1987#ifndef ImDrawCallback
     1988typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd);
     1989#endif
     1990
     1991// Special Draw callback value to request renderer back-end to reset the graphics/render state.
     1992// The renderer back-end needs to handle this special value, otherwise it will crash trying to call a function at this address.
     1993// This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored.
     1994// It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call).
     1995#define ImDrawCallback_ResetRenderState     (ImDrawCallback)(-1)
    14771996
    14781997// Typically, 1 command = 1 GPU draw call (unless command is a callback)
     1998// - VtxOffset/IdxOffset: When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset' is enabled,
     1999//   those fields allow us to render meshes larger than 64K vertices while keeping 16-bit indices.
     2000//   Pre-1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields.
     2001// - The ClipRect/TextureId/VtxOffset fields must be contiguous as we memcmp() them together (this is asserted for).
    14792002struct ImDrawCmd
    14802003{
    1481    unsigned int    ElemCount;              // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[].
    1482    ImVec4          ClipRect;               // Clipping rectangle (x1, y1, x2, y2)
    1483    ImTextureID     TextureId;              // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas.
    1484    ImDrawCallback  UserCallback;           // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
    1485    void*           UserCallbackData;       // The draw callback code can access this.
    1486 
    1487    ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = ClipRect.z = ClipRect.w = 0.0f; TextureId = NULL; UserCallback = NULL; UserCallbackData = NULL; }
    1488 };
    1489 
    1490 // Vertex index (override with '#define ImDrawIdx unsigned int' inside in imconfig.h)
     2004    ImVec4          ClipRect;           // 4*4  // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates
     2005    ImTextureID     TextureId;          // 4-8  // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas.
     2006    unsigned int    VtxOffset;          // 4    // Start offset in vertex buffer. ImGuiBackendFlags_RendererHasVtxOffset: always 0, otherwise may be >0 to support meshes larger than 64K vertices with 16-bit indices.
     2007    unsigned int    IdxOffset;          // 4    // Start offset in index buffer. Always equal to sum of ElemCount drawn so far.
     2008    unsigned int    ElemCount;          // 4    // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[].
     2009    ImDrawCallback  UserCallback;       // 4-8  // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
     2010    void*           UserCallbackData;   // 4-8  // The draw callback code can access this.
     2011
     2012    ImDrawCmd() { memset(this, 0, sizeof(*this)); } // Also ensure our padding fields are zeroed
     2013};
     2014
     2015// Vertex index, default to 16-bit
     2016// To allow large meshes with 16-bit indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end (recommended).
     2017// To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in imconfig.h.
    14912018#ifndef ImDrawIdx
    14922019typedef unsigned short ImDrawIdx;
     
    14972024struct ImDrawVert
    14982025{
    1499    ImVec2  pos;
    1500    ImVec2  uv;
    1501    ImU32   col;
     2026    ImVec2  pos;
     2027    ImVec2  uv;
     2028    ImU32   col;
    15022029};
    15032030#else
    15042031// You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h
    15052032// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine.
    1506 // The type has to be described within the macro (you can either declare the struct or use a typedef)
    1507 // NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM. 
     2033// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared a the time you'd want to set your type up.
     2034// NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM.
    15082035IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT;
    15092036#endif
    15102037
    1511 // Draw channels are used by the Columns API to "split" the render list into different channels while building, so items of each column can be batched together.
    1512 // You can also use them to simulate drawing layers and submit primitives in a different order than how they will be rendered.
     2038// For use by ImDrawListSplitter.
    15132039struct ImDrawChannel
    15142040{
    1515    ImVector<ImDrawCmd>     CmdBuffer;
    1516    ImVector<ImDrawIdx>     IdxBuffer;
     2041    ImVector<ImDrawCmd>         _CmdBuffer;
     2042    ImVector<ImDrawIdx>         _IdxBuffer;
     2043};
     2044
     2045// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order.
     2046// This is used by the Columns api, so items of each column can be batched together in a same draw call.
     2047struct ImDrawListSplitter
     2048{
     2049    int                         _Current;    // Current channel number (0)
     2050    int                         _Count;      // Number of active channels (1+)
     2051    ImVector<ImDrawChannel>     _Channels;   // Draw channels (not resized down so _Count might be < Channels.Size)
     2052
     2053    inline ImDrawListSplitter()  { Clear(); }
     2054    inline ~ImDrawListSplitter() { ClearFreeMemory(); }
     2055    inline void                 Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame
     2056    IMGUI_API void              ClearFreeMemory();
     2057    IMGUI_API void              Split(ImDrawList* draw_list, int count);
     2058    IMGUI_API void              Merge(ImDrawList* draw_list);
     2059    IMGUI_API void              SetCurrentChannel(ImDrawList* draw_list, int channel_idx);
    15172060};
    15182061
    15192062enum ImDrawCornerFlags_
    15202063{
    1521    ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1
    1522    ImDrawCornerFlags_TopRight = 1 << 1, // 0x2
    1523    ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4
    1524    ImDrawCornerFlags_BotRight = 1 << 3, // 0x8
    1525    ImDrawCornerFlags_Top = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight,   // 0x3
    1526    ImDrawCornerFlags_Bot = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight,   // 0xC
    1527    ImDrawCornerFlags_Left = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft,    // 0x5
    1528    ImDrawCornerFlags_Right = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight,  // 0xA
    1529    ImDrawCornerFlags_All = 0xF     // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience
    1530 };
    1531 
     2064    ImDrawCornerFlags_None      = 0,
     2065    ImDrawCornerFlags_TopLeft   = 1 << 0, // 0x1
     2066    ImDrawCornerFlags_TopRight  = 1 << 1, // 0x2
     2067    ImDrawCornerFlags_BotLeft   = 1 << 2, // 0x4
     2068    ImDrawCornerFlags_BotRight  = 1 << 3, // 0x8
     2069    ImDrawCornerFlags_Top       = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_TopRight,   // 0x3
     2070    ImDrawCornerFlags_Bot       = ImDrawCornerFlags_BotLeft | ImDrawCornerFlags_BotRight,   // 0xC
     2071    ImDrawCornerFlags_Left      = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotLeft,    // 0x5
     2072    ImDrawCornerFlags_Right     = ImDrawCornerFlags_TopRight | ImDrawCornerFlags_BotRight,  // 0xA
     2073    ImDrawCornerFlags_All       = 0xF     // In your function calls you may use ~0 (= all bits sets) instead of ImDrawCornerFlags_All, as a convenience
     2074};
     2075
     2076// Flags for ImDrawList. Those are set automatically by ImGui:: functions from ImGuiIO settings, and generally not manipulated directly.
     2077// It is however possible to temporarily alter flags between calls to ImDrawList:: functions.
    15322078enum ImDrawListFlags_
    15332079{
    1534    ImDrawListFlags_AntiAliasedLines = 1 << 0,
    1535    ImDrawListFlags_AntiAliasedFill = 1 << 1
     2080    ImDrawListFlags_None                    = 0,
     2081    ImDrawListFlags_AntiAliasedLines        = 1 << 0,  // Enable anti-aliased lines/borders (*2 the number of triangles for 1.0f wide line or lines thin enough to be drawn using textures, otherwise *3 the number of triangles)
     2082    ImDrawListFlags_AntiAliasedLinesUseTex  = 1 << 1,  // Enable anti-aliased lines/borders using textures when possible. Require back-end to render with bilinear filtering.
     2083    ImDrawListFlags_AntiAliasedFill         = 1 << 2,  // Enable anti-aliased edge around filled shapes (rounded rectangles, circles).
     2084    ImDrawListFlags_AllowVtxOffset          = 1 << 3   // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled.
    15362085};
    15372086
    15382087// Draw command list
    1539 // This is the low-level list of polygons that ImGui functions are filling. At the end of the frame, all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering.
    1540 // Each ImGui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to access the current window draw list and draw custom primitives.
     2088// This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame,
     2089// all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering.
     2090// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to
     2091// access the current window draw list and draw custom primitives.
    15412092// You can interleave normal ImGui:: calls and adding primitives to the current draw list.
    1542 // All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), however you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well)
     2093// All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), but you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well)
    15432094// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects.
    15442095struct ImDrawList
    15452096{
    1546    // This is what you have to render
    1547    ImVector<ImDrawCmd>     CmdBuffer;          // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback.
    1548    ImVector<ImDrawIdx>     IdxBuffer;          // Index buffer. Each command consume ImDrawCmd::ElemCount of those
    1549    ImVector<ImDrawVert>    VtxBuffer;          // Vertex buffer.
    1550    ImDrawListFlags         Flags;              // Flags, you may poke into these to adjust anti-aliasing settings per-primitive.
    1551 
    1552                                                // [Internal, used while building lists]
    1553    const ImDrawListSharedData* _Data;          // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context)
    1554    const char*             _OwnerName;         // Pointer to owner window's name for debugging
    1555    unsigned int            _VtxCurrentIdx;     // [Internal] == VtxBuffer.Size
    1556    ImDrawVert*             _VtxWritePtr;       // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
    1557    ImDrawIdx*              _IdxWritePtr;       // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
    1558    ImVector<ImVec4>        _ClipRectStack;     // [Internal]
    1559    ImVector<ImTextureID>   _TextureIdStack;    // [Internal]
    1560    ImVector<ImVec2>        _Path;              // [Internal] current path building
    1561    int                     _ChannelsCurrent;   // [Internal] current channel number (0)
    1562    int                     _ChannelsCount;     // [Internal] number of active channels (1+)
    1563    ImVector<ImDrawChannel> _Channels;          // [Internal] draw channels for columns API (not resized down so _ChannelsCount may be smaller than _Channels.Size)
    1564 
    1565                                                // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui)
    1566    ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; _OwnerName = NULL; Clear(); }
    1567    ~ImDrawList() { ClearFreeMemory(); }
    1568    IMGUI_API void  PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false);  // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
    1569    IMGUI_API void  PushClipRectFullScreen();
    1570    IMGUI_API void  PopClipRect();
    1571    IMGUI_API void  PushTextureID(ImTextureID texture_id);
    1572    IMGUI_API void  PopTextureID();
    1573    inline ImVec2   GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); }
    1574    inline ImVec2   GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); }
    1575 
    1576    // Primitives
    1577    IMGUI_API void  AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f);
    1578    IMGUI_API void  AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All, float thickness = 1.0f);   // a: upper-left, b: lower-right, rounding_corners_flags: 4-bits corresponding to which corner to round
    1579    IMGUI_API void  AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All);                     // a: upper-left, b: lower-right
    1580    IMGUI_API void  AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left);
    1581    IMGUI_API void  AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness = 1.0f);
    1582    IMGUI_API void  AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col);
    1583    IMGUI_API void  AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness = 1.0f);
    1584    IMGUI_API void  AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col);
    1585    IMGUI_API void  AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f);
    1586    IMGUI_API void  AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12);
    1587    IMGUI_API void  AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
    1588    IMGUI_API void  AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);
    1589    IMGUI_API void  AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a = ImVec2(0, 0), const ImVec2& uv_b = ImVec2(1, 1), ImU32 col = 0xFFFFFFFF);
    1590    IMGUI_API void  AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a = ImVec2(0, 0), const ImVec2& uv_b = ImVec2(1, 0), const ImVec2& uv_c = ImVec2(1, 1), const ImVec2& uv_d = ImVec2(0, 1), ImU32 col = 0xFFFFFFFF);
    1591    IMGUI_API void  AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners = ImDrawCornerFlags_All);
    1592    IMGUI_API void  AddPolyline(const ImVec2* points, const int num_points, ImU32 col, bool closed, float thickness);
    1593    IMGUI_API void  AddConvexPolyFilled(const ImVec2* points, const int num_points, ImU32 col);
    1594    IMGUI_API void  AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0);
    1595 
    1596    // Stateful path API, add points then finish with PathFill() or PathStroke()
    1597    inline    void  PathClear() { _Path.resize(0); }
    1598    inline    void  PathLineTo(const ImVec2& pos) { _Path.push_back(pos); }
    1599    inline    void  PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); }
    1600    inline    void  PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); PathClear(); }
    1601    inline    void  PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); PathClear(); }
    1602    IMGUI_API void  PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10);
    1603    IMGUI_API void  PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12);                                // Use precomputed angles for a 12 steps circle
    1604    IMGUI_API void  PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0);
    1605    IMGUI_API void  PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All);
    1606 
    1607    // Channels
    1608    // - Use to simulate layers. By switching channels to can render out-of-order (e.g. submit foreground primitives before background primitives)
    1609    // - Use to minimize draw calls (e.g. if going back-and-forth between multiple non-overlapping clipping rectangles, prefer to append into separate channels then merge at the end)
    1610    IMGUI_API void  ChannelsSplit(int channels_count);
    1611    IMGUI_API void  ChannelsMerge();
    1612    IMGUI_API void  ChannelsSetCurrent(int channel_index);
    1613 
    1614    // Advanced
    1615    IMGUI_API void  AddCallback(ImDrawCallback callback, void* callback_data);  // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles.
    1616    IMGUI_API void  AddDrawCmd();                                               // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
    1617    IMGUI_API ImDrawList* CloneOutput() const;                                  // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer.
    1618 
    1619                                                                                // Internal helpers
    1620                                                                                // NB: all primitives needs to be reserved via PrimReserve() beforehand!
    1621    IMGUI_API void  Clear();
    1622    IMGUI_API void  ClearFreeMemory();
    1623    IMGUI_API void  PrimReserve(int idx_count, int vtx_count);
    1624    IMGUI_API void  PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col);      // Axis aligned rectangle (composed of two triangles)
    1625    IMGUI_API void  PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col);
    1626    IMGUI_API void  PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col);
    1627    inline    void  PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; }
    1628    inline    void  PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; }
    1629    inline    void  PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); }
    1630    IMGUI_API void  UpdateClipRect();
    1631    IMGUI_API void  UpdateTextureID();
    1632 };
    1633 
    1634 // All draw data to render an ImGui frame
    1635 // (NB: the style and the naming convention here is a little inconsistent but we preserve them for backward compatibility purpose)
     2097    // This is what you have to render
     2098    ImVector<ImDrawCmd>     CmdBuffer;          // Draw commands. Typically 1 command = 1 GPU draw call, unless the command is a callback.
     2099    ImVector<ImDrawIdx>     IdxBuffer;          // Index buffer. Each command consume ImDrawCmd::ElemCount of those
     2100    ImVector<ImDrawVert>    VtxBuffer;          // Vertex buffer.
     2101    ImDrawListFlags         Flags;              // Flags, you may poke into these to adjust anti-aliasing settings per-primitive.
     2102
     2103    // [Internal, used while building lists]
     2104    const ImDrawListSharedData* _Data;          // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context)
     2105    const char*             _OwnerName;         // Pointer to owner window's name for debugging
     2106    unsigned int            _VtxCurrentIdx;     // [Internal] Generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0.
     2107    ImDrawVert*             _VtxWritePtr;       // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
     2108    ImDrawIdx*              _IdxWritePtr;       // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
     2109    ImVector<ImVec4>        _ClipRectStack;     // [Internal]
     2110    ImVector<ImTextureID>   _TextureIdStack;    // [Internal]
     2111    ImVector<ImVec2>        _Path;              // [Internal] current path building
     2112    ImDrawCmd               _CmdHeader;         // [Internal] Template of active commands. Fields should match those of CmdBuffer.back().
     2113    ImDrawListSplitter      _Splitter;          // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!)
     2114
     2115    // If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui)
     2116    ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; Flags = ImDrawListFlags_None; _VtxCurrentIdx = 0; _VtxWritePtr = NULL; _IdxWritePtr = NULL; _OwnerName = NULL; }
     2117
     2118    ~ImDrawList() { _ClearFreeMemory(); }
     2119    IMGUI_API void  PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect = false);  // Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
     2120    IMGUI_API void  PushClipRectFullScreen();
     2121    IMGUI_API void  PopClipRect();
     2122    IMGUI_API void  PushTextureID(ImTextureID texture_id);
     2123    IMGUI_API void  PopTextureID();
     2124    inline ImVec2   GetClipRectMin() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.x, cr.y); }
     2125    inline ImVec2   GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); }
     2126
     2127    // Primitives
     2128    // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners.
     2129    // - For circle primitives, use "num_segments == 0" to automatically calculate tessellation (preferred).
     2130    //   In older versions (until Dear ImGui 1.77) the AddCircle functions defaulted to num_segments == 12.
     2131    //   In future versions we will use textures to provide cheaper and higher-quality circles.
     2132    //   Use AddNgon() and AddNgonFilled() functions if you need to guaranteed a specific number of sides.
     2133    IMGUI_API void  AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f);
     2134    IMGUI_API void  AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f);   // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4 bits corresponding to which corner to round
     2135    IMGUI_API void  AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All);                     // a: upper-left, b: lower-right (== upper-left + size)
     2136    IMGUI_API void  AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left);
     2137    IMGUI_API void  AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f);
     2138    IMGUI_API void  AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col);
     2139    IMGUI_API void  AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f);
     2140    IMGUI_API void  AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col);
     2141    IMGUI_API void  AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 0, float thickness = 1.0f);
     2142    IMGUI_API void  AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 0);
     2143    IMGUI_API void  AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness = 1.0f);
     2144    IMGUI_API void  AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments);
     2145    IMGUI_API void  AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
     2146    IMGUI_API void  AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);
     2147    IMGUI_API void  AddPolyline(const ImVec2* points, int num_points, ImU32 col, bool closed, float thickness);
     2148    IMGUI_API void  AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); // Note: Anti-aliased filling requires points to be in clockwise order.
     2149    IMGUI_API void  AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0);
     2150
     2151    // Image primitives
     2152    // - Read FAQ to understand what ImTextureID is.
     2153    // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle.
     2154    // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture.
     2155    IMGUI_API void  AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE);
     2156    IMGUI_API void  AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE);
     2157    IMGUI_API void  AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All);
     2158
     2159    // Stateful path API, add points then finish with PathFillConvex() or PathStroke()
     2160    inline    void  PathClear()                                                 { _Path.Size = 0; }
     2161    inline    void  PathLineTo(const ImVec2& pos)                               { _Path.push_back(pos); }
     2162    inline    void  PathLineToMergeDuplicate(const ImVec2& pos)                 { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size - 1], &pos, 8) != 0) _Path.push_back(pos); }
     2163    inline    void  PathFillConvex(ImU32 col)                                   { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; }  // Note: Anti-aliased filling requires points to be in clockwise order.
     2164    inline    void  PathStroke(ImU32 col, bool closed, float thickness = 1.0f)  { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; }
     2165    IMGUI_API void  PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10);
     2166    IMGUI_API void  PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12);                                            // Use precomputed angles for a 12 steps circle
     2167    IMGUI_API void  PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0);
     2168    IMGUI_API void  PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All);
     2169
     2170    // Advanced
     2171    IMGUI_API void  AddCallback(ImDrawCallback callback, void* callback_data);  // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles.
     2172    IMGUI_API void  AddDrawCmd();                                               // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
     2173    IMGUI_API ImDrawList* CloneOutput() const;                                  // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer.
     2174
     2175    // Advanced: Channels
     2176    // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives)
     2177    // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end)
     2178    // - FIXME-OBSOLETE: This API shouldn't have been in ImDrawList in the first place!
     2179    //   Prefer using your own persistent instance of ImDrawListSplitter as you can stack them.
     2180    //   Using the ImDrawList::ChannelsXXXX you cannot stack a split over another.
     2181    inline void     ChannelsSplit(int count)    { _Splitter.Split(this, count); }
     2182    inline void     ChannelsMerge()             { _Splitter.Merge(this); }
     2183    inline void     ChannelsSetCurrent(int n)   { _Splitter.SetCurrentChannel(this, n); }
     2184
     2185    // Advanced: Primitives allocations
     2186    // - We render triangles (three vertices)
     2187    // - All primitives needs to be reserved via PrimReserve() beforehand.
     2188    IMGUI_API void  PrimReserve(int idx_count, int vtx_count);
     2189    IMGUI_API void  PrimUnreserve(int idx_count, int vtx_count);
     2190    IMGUI_API void  PrimRect(const ImVec2& a, const ImVec2& b, ImU32 col);      // Axis aligned rectangle (composed of two triangles)
     2191    IMGUI_API void  PrimRectUV(const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col);
     2192    IMGUI_API void  PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col);
     2193    inline    void  PrimWriteVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col)    { _VtxWritePtr->pos = pos; _VtxWritePtr->uv = uv; _VtxWritePtr->col = col; _VtxWritePtr++; _VtxCurrentIdx++; }
     2194    inline    void  PrimWriteIdx(ImDrawIdx idx)                                     { *_IdxWritePtr = idx; _IdxWritePtr++; }
     2195    inline    void  PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col)         { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index
     2196
     2197    // [Internal helpers]
     2198    IMGUI_API void  _ResetForNewFrame();
     2199    IMGUI_API void  _ClearFreeMemory();
     2200    IMGUI_API void  _PopUnusedDrawCmd();
     2201    IMGUI_API void  _OnChangedClipRect();
     2202    IMGUI_API void  _OnChangedTextureID();
     2203    IMGUI_API void  _OnChangedVtxOffset();
     2204};
     2205
     2206// All draw data to render a Dear ImGui frame
     2207// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose,
     2208// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList)
    16362209struct ImDrawData
    16372210{
    1638    bool            Valid;                  // Only valid after Render() is called and before the next NewFrame() is called.
    1639    ImDrawList**    CmdLists;               // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here.
    1640    int             CmdListsCount;          // Number of ImDrawList* to render
    1641    int             TotalIdxCount;          // For convenience, sum of all ImDrawList's IdxBuffer.Size
    1642    int             TotalVtxCount;          // For convenience, sum of all ImDrawList's VtxBuffer.Size
    1643 
    1644                                            // Functions
    1645    ImDrawData() { Valid = false; Clear(); }
    1646    ~ImDrawData() { Clear(); }
    1647    void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; } // The ImDrawList are owned by ImGuiContext!
    1648    IMGUI_API void  DeIndexAllBuffers();                // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
    1649    IMGUI_API void  ScaleClipRects(const ImVec2& sc);   // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
    1650 };
     2211    bool            Valid;                  // Only valid after Render() is called and before the next NewFrame() is called.
     2212    ImDrawList**    CmdLists;               // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here.
     2213    int             CmdListsCount;          // Number of ImDrawList* to render
     2214    int             TotalIdxCount;          // For convenience, sum of all ImDrawList's IdxBuffer.Size
     2215    int             TotalVtxCount;          // For convenience, sum of all ImDrawList's VtxBuffer.Size
     2216    ImVec2          DisplayPos;             // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use)
     2217    ImVec2          DisplaySize;            // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use)
     2218    ImVec2          FramebufferScale;       // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display.
     2219
     2220    // Functions
     2221    ImDrawData()    { Valid = false; Clear(); }
     2222    ~ImDrawData()   { Clear(); }
     2223    void Clear()    { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext!
     2224    IMGUI_API void  DeIndexAllBuffers();                    // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
     2225    IMGUI_API void  ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
     2226};
     2227
     2228//-----------------------------------------------------------------------------
     2229// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont)
     2230//-----------------------------------------------------------------------------
    16512231
    16522232struct ImFontConfig
    16532233{
    1654    void*           FontData;               //          // TTF/OTF data
    1655    int             FontDataSize;           //          // TTF/OTF data size
    1656    bool            FontDataOwnedByAtlas;   // true     // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself).
    1657    int             FontNo;                 // 0        // Index of font within TTF/OTF file
    1658    float           SizePixels;             //          // Size in pixels for rasterizer.
    1659    int             OversampleH;            // 3        // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis.
    1660    int             OversampleV;            // 1        // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis.
    1661    bool            PixelSnapH;             // false    // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1.
    1662    ImVec2          GlyphExtraSpacing;      // 0, 0     // Extra spacing (in pixels) between glyphs. Only X axis is supported for now.
    1663    ImVec2          GlyphOffset;            // 0, 0     // Offset all glyphs from this font input.
    1664    const ImWchar*  GlyphRanges;            // NULL     // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE.
    1665    bool            MergeMode;              // false    // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
    1666    unsigned int    RasterizerFlags;        // 0x00     // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one.
    1667    float           RasterizerMultiply;     // 1.0f     // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable.
    1668 
    1669                                            // [Internal]
    1670    char            Name[40];               // Name (strictly to ease debugging)
    1671    ImFont*         DstFont;
    1672 
    1673    IMGUI_API ImFontConfig();
    1674 };
    1675 
     2234    void*           FontData;               //          // TTF/OTF data
     2235    int             FontDataSize;           //          // TTF/OTF data size
     2236    bool            FontDataOwnedByAtlas;   // true     // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself).
     2237    int             FontNo;                 // 0        // Index of font within TTF/OTF file
     2238    float           SizePixels;             //          // Size in pixels for rasterizer (more or less maps to the resulting font height).
     2239    int             OversampleH;            // 3        // Rasterize at higher quality for sub-pixel positioning. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details.
     2240    int             OversampleV;            // 1        // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis.
     2241    bool            PixelSnapH;             // false    // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1.
     2242    ImVec2          GlyphExtraSpacing;      // 0, 0     // Extra spacing (in pixels) between glyphs. Only X axis is supported for now.
     2243    ImVec2          GlyphOffset;            // 0, 0     // Offset all glyphs from this font input.
     2244    const ImWchar*  GlyphRanges;            // NULL     // Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list). THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE.
     2245    float           GlyphMinAdvanceX;       // 0        // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font
     2246    float           GlyphMaxAdvanceX;       // FLT_MAX  // Maximum AdvanceX for glyphs
     2247    bool            MergeMode;              // false    // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
     2248    unsigned int    RasterizerFlags;        // 0x00     // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one.
     2249    float           RasterizerMultiply;     // 1.0f     // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable.
     2250    ImWchar         EllipsisChar;           // -1       // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used.
     2251
     2252    // [Internal]
     2253    char            Name[40];               // Name (strictly to ease debugging)
     2254    ImFont*         DstFont;
     2255
     2256    IMGUI_API ImFontConfig();
     2257};
     2258
     2259// Hold rendering data for one glyph.
     2260// (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this)
    16762261struct ImFontGlyph
    16772262{
    1678    ImWchar         Codepoint;          // 0x0000..0xFFFF
    1679    float           AdvanceX;           // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in)
    1680    float           X0, Y0, X1, Y1;     // Glyph corners
    1681    float           U0, V0, U1, V1;     // Texture coordinates
    1682 };
    1683 
     2263    unsigned int    Codepoint : 31;     // 0x0000..0xFFFF
     2264    unsigned int    Visible : 1;        // Flag to allow early out when rendering
     2265    float           AdvanceX;           // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in)
     2266    float           X0, Y0, X1, Y1;     // Glyph corners
     2267    float           U0, V0, U1, V1;     // Texture coordinates
     2268};
     2269
     2270// Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges().
     2271// This is essentially a tightly packed of vector of 64k booleans = 8KB storage.
     2272struct ImFontGlyphRangesBuilder
     2273{
     2274    ImVector<ImU32> UsedChars;            // Store 1-bit per Unicode code point (0=unused, 1=used)
     2275
     2276    ImFontGlyphRangesBuilder()              { Clear(); }
     2277    inline void     Clear()                 { int size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); }
     2278    inline bool     GetBit(size_t n) const  { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; }  // Get bit n in the array
     2279    inline void     SetBit(size_t n)        { int off = (int)(n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; }               // Set bit n in the array
     2280    inline void     AddChar(ImWchar c)      { SetBit(c); }                      // Add character
     2281    IMGUI_API void  AddText(const char* text, const char* text_end = NULL);     // Add string (each character of the UTF-8 string are added)
     2282    IMGUI_API void  AddRanges(const ImWchar* ranges);                           // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext
     2283    IMGUI_API void  BuildRanges(ImVector<ImWchar>* out_ranges);                 // Output new ranges
     2284};
     2285
     2286// See ImFontAtlas::AddCustomRectXXX functions.
     2287struct ImFontAtlasCustomRect
     2288{
     2289    unsigned short  Width, Height;  // Input    // Desired rectangle dimension
     2290    unsigned short  X, Y;           // Output   // Packed position in Atlas
     2291    unsigned int    GlyphID;        // Input    // For custom font glyphs only (ID < 0x110000)
     2292    float           GlyphAdvanceX;  // Input    // For custom font glyphs only: glyph xadvance
     2293    ImVec2          GlyphOffset;    // Input    // For custom font glyphs only: glyph display offset
     2294    ImFont*         Font;           // Input    // For custom font glyphs only: target font
     2295    ImFontAtlasCustomRect()         { Width = Height = 0; X = Y = 0xFFFF; GlyphID = 0; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; }
     2296    bool IsPacked() const           { return X != 0xFFFF; }
     2297};
     2298
     2299// Flags for ImFontAtlas build
    16842300enum ImFontAtlasFlags_
    16852301{
    1686    ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0,   // Don't round the height to next power of two
    1687    ImFontAtlasFlags_NoMouseCursors = 1 << 1    // Don't build software mouse cursors into the atlas
    1688 };
    1689 
    1690 // Load and rasterize multiple TTF/OTF fonts into a same texture.
    1691 // Sharing a texture for multiple fonts allows us to reduce the number of draw calls during rendering.
    1692 // We also add custom graphic data into the texture that serves for ImGui.
    1693 //  1. (Optional) Call AddFont*** functions. If you don't call any, the default font will be loaded for you.
    1694 //  2. Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.
    1695 //  3. Upload the pixels data into a texture within your graphics system.
    1696 //  4. Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture. This value will be passed back to you during rendering to identify the texture.
    1697 // IMPORTANT: If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the ImFont is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data.
     2302    ImFontAtlasFlags_None               = 0,
     2303    ImFontAtlasFlags_NoPowerOfTwoHeight = 1 << 0,   // Don't round the height to next power of two
     2304    ImFontAtlasFlags_NoMouseCursors     = 1 << 1,   // Don't build software mouse cursors into the atlas (save a little texture memory)
     2305    ImFontAtlasFlags_NoBakedLines       = 1 << 2    // Don't build thick line textures into the atlas (save a little texture memory). The AntiAliasedLinesUseTex features uses them, otherwise they will be rendered using polygons (more expensive for CPU/GPU).
     2306};
     2307
     2308// Load and rasterize multiple TTF/OTF fonts into a same texture. The font atlas will build a single texture holding:
     2309//  - One or more fonts.
     2310//  - Custom graphics data needed to render the shapes needed by Dear ImGui.
     2311//  - Mouse cursor shapes for software cursor rendering (unless setting 'Flags |= ImFontAtlasFlags_NoMouseCursors' in the font atlas).
     2312// It is the user-code responsibility to setup/build the atlas, then upload the pixel data into a texture accessible by your graphics api.
     2313//  - Optionally, call any of the AddFont*** functions. If you don't call any, the default font embedded in the code will be loaded for you.
     2314//  - Call GetTexDataAsAlpha8() or GetTexDataAsRGBA32() to build and retrieve pixels data.
     2315//  - Upload the pixels data into a texture within your graphics system (see imgui_impl_xxxx.cpp examples)
     2316//  - Call SetTexID(my_tex_id); and pass the pointer/identifier to your texture in a format natural to your graphics API.
     2317//    This value will be passed back to you during rendering to identify the texture. Read FAQ entry about ImTextureID for more details.
     2318// Common pitfalls:
     2319// - If you pass a 'glyph_ranges' array to AddFont*** functions, you need to make sure that your array persist up until the
     2320//   atlas is build (when calling GetTexData*** or Build()). We only copy the pointer, not the data.
     2321// - Important: By default, AddFontFromMemoryTTF() takes ownership of the data. Even though we are not writing to it, we will free the pointer on destruction.
     2322//   You can set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed,
     2323// - Even though many functions are suffixed with "TTF", OTF data is supported just as well.
     2324// - This is an old API and it is currently awkward for those and and various other reasons! We will address them in the future!
    16982325struct ImFontAtlas
    16992326{
    1700    IMGUI_API ImFontAtlas();
    1701    IMGUI_API ~ImFontAtlas();
    1702    IMGUI_API ImFont*           AddFont(const ImFontConfig* font_cfg);
    1703    IMGUI_API ImFont*           AddFontDefault(const ImFontConfig* font_cfg = NULL);
    1704    IMGUI_API ImFont*           AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL);
    1705    IMGUI_API ImFont*           AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after Build(). Set font_cfg->FontDataOwnedByAtlas to false to keep ownership.
    1706    IMGUI_API ImFont*           AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp.
    1707    IMGUI_API ImFont*           AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL);              // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter.
    1708    IMGUI_API void              ClearInputData();           // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts.
    1709    IMGUI_API void              ClearTexData();             // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory.
    1710    IMGUI_API void              ClearFonts();               // Clear output font data (glyphs storage, UV coordinates).
    1711    IMGUI_API void              Clear();                    // Clear all input and output.
    1712 
    1713                                                            // Build atlas, retrieve pixel data.
    1714                                                            // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID().
    1715                                                            // RGBA32 format is provided for convenience and compatibility, but note that unless you use CustomRect to draw color data, the RGB pixels emitted from Fonts will all be white (~75% of waste).
    1716                                                            // Pitch = Width * BytesPerPixels
    1717    IMGUI_API bool              Build();                    // Build pixels data. This is called automatically for you by the GetTexData*** functions.
    1718    IMGUI_API void              GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);  // 1 byte per-pixel
    1719    IMGUI_API void              GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);  // 4 bytes-per-pixel
    1720    void                        SetTexID(ImTextureID id) { TexID = id; }
    1721 
    1722    //-------------------------------------------
    1723    // Glyph Ranges
    1724    //-------------------------------------------
    1725 
    1726    // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list)
    1727    // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details.
    1728    IMGUI_API const ImWchar*    GetGlyphRangesDefault();    // Basic Latin, Extended Latin
    1729    IMGUI_API const ImWchar*    GetGlyphRangesKorean();     // Default + Korean characters
    1730    IMGUI_API const ImWchar*    GetGlyphRangesJapanese();   // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
    1731    IMGUI_API const ImWchar*    GetGlyphRangesChinese();    // Default + Japanese + full set of about 21000 CJK Unified Ideographs
    1732    IMGUI_API const ImWchar*    GetGlyphRangesCyrillic();   // Default + about 400 Cyrillic characters
    1733    IMGUI_API const ImWchar*    GetGlyphRangesThai();       // Default + Thai characters
    1734 
    1735                                                            // Helpers to build glyph ranges from text data. Feed your application strings/characters to it then call BuildRanges().
    1736    struct GlyphRangesBuilder
    1737    {
    1738       ImVector<unsigned char> UsedChars;  // Store 1-bit per Unicode code point (0=unused, 1=used)
    1739       GlyphRangesBuilder() { UsedChars.resize(0x10000 / 8); memset(UsedChars.Data, 0, 0x10000 / 8); }
    1740       bool           GetBit(int n) { return (UsedChars[n >> 3] & (1 << (n & 7))) != 0; }
    1741       void           SetBit(int n) { UsedChars[n >> 3] |= 1 << (n & 7); }  // Set bit 'c' in the array
    1742       void           AddChar(ImWchar c) { SetBit(c); }                          // Add character
    1743       IMGUI_API void AddText(const char* text, const char* text_end = NULL);      // Add string (each character of the UTF-8 string are added)
    1744       IMGUI_API void AddRanges(const ImWchar* ranges);                            // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault) to force add all of ASCII/Latin+Ext
    1745       IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges);                  // Output new ranges
    1746    };
    1747 
    1748    //-------------------------------------------
    1749    // Custom Rectangles/Glyphs API
    1750    //-------------------------------------------
    1751 
    1752    // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. After calling Build(), you can query the rectangle position and render your pixels.
    1753    // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs.
    1754    struct CustomRect
    1755    {
    1756       unsigned int    ID;             // Input    // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data.
    1757       unsigned short  Width, Height;  // Input    // Desired rectangle dimension
    1758       unsigned short  X, Y;           // Output   // Packed position in Atlas
    1759       float           GlyphAdvanceX;  // Input    // For custom font glyphs only (ID<0x10000): glyph xadvance
    1760       ImVec2          GlyphOffset;    // Input    // For custom font glyphs only (ID<0x10000): glyph display offset
    1761       ImFont*         Font;           // Input    // For custom font glyphs only (ID<0x10000): target font
    1762       CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0, 0); Font = NULL; }
    1763       bool IsPacked() const { return X != 0xFFFF; }
    1764    };
    1765 
    1766    IMGUI_API int       AddCustomRectRegular(unsigned int id, int width, int height);                                                                   // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList
    1767    IMGUI_API int       AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0));   // Id needs to be < 0x10000 to register a rectangle to map into a specific font.
    1768    const CustomRect*   GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; }
    1769 
    1770    // [Internal]
    1771    IMGUI_API void      CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max);
    1772    IMGUI_API bool      GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
    1773 
    1774    //-------------------------------------------
    1775    // Members
    1776    //-------------------------------------------
    1777 
    1778    ImFontAtlasFlags            Flags;              // Build flags (see ImFontAtlasFlags_)
    1779    ImTextureID                 TexID;              // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.
    1780    int                         TexDesiredWidth;    // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
    1781    int                         TexGlyphPadding;    // Padding between glyphs within texture in pixels. Defaults to 1.
    1782 
    1783                                                    // [Internal]
    1784                                                    // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.
    1785    unsigned char*              TexPixelsAlpha8;    // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight
    1786    unsigned int*               TexPixelsRGBA32;    // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4
    1787    int                         TexWidth;           // Texture width calculated during Build().
    1788    int                         TexHeight;          // Texture height calculated during Build().
    1789    ImVec2                      TexUvScale;         // = (1.0f/TexWidth, 1.0f/TexHeight)
    1790    ImVec2                      TexUvWhitePixel;    // Texture coordinates to a white pixel
    1791    ImVector<ImFont*>           Fonts;              // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font.
    1792    ImVector<CustomRect>        CustomRects;        // Rectangles for packing custom texture data into the atlas.
    1793    ImVector<ImFontConfig>      ConfigData;         // Internal data
    1794    int                         CustomRectIds[1];   // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList
     2327    IMGUI_API ImFontAtlas();
     2328    IMGUI_API ~ImFontAtlas();
     2329    IMGUI_API ImFont*           AddFont(const ImFontConfig* font_cfg);
     2330    IMGUI_API ImFont*           AddFontDefault(const ImFontConfig* font_cfg = NULL);
     2331    IMGUI_API ImFont*           AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL);
     2332    IMGUI_API ImFont*           AddFontFromMemoryTTF(void* font_data, int font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // Note: Transfer ownership of 'ttf_data' to ImFontAtlas! Will be deleted after destruction of the atlas. Set font_cfg->FontDataOwnedByAtlas=false to keep ownership of your data and it won't be freed.
     2333    IMGUI_API ImFont*           AddFontFromMemoryCompressedTTF(const void* compressed_font_data, int compressed_font_size, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL); // 'compressed_font_data' still owned by caller. Compress with binary_to_compressed_c.cpp.
     2334    IMGUI_API ImFont*           AddFontFromMemoryCompressedBase85TTF(const char* compressed_font_data_base85, float size_pixels, const ImFontConfig* font_cfg = NULL, const ImWchar* glyph_ranges = NULL);              // 'compressed_font_data_base85' still owned by caller. Compress with binary_to_compressed_c.cpp with -base85 parameter.
     2335    IMGUI_API void              ClearInputData();           // Clear input data (all ImFontConfig structures including sizes, TTF data, glyph ranges, etc.) = all the data used to build the texture and fonts.
     2336    IMGUI_API void              ClearTexData();             // Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory.
     2337    IMGUI_API void              ClearFonts();               // Clear output font data (glyphs storage, UV coordinates).
     2338    IMGUI_API void              Clear();                    // Clear all input and output.
     2339
     2340    // Build atlas, retrieve pixel data.
     2341    // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID().
     2342    // The pitch is always = Width * BytesPerPixels (1 or 4)
     2343    // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into
     2344    // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste.
     2345    IMGUI_API bool              Build();                    // Build pixels data. This is called automatically for you by the GetTexData*** functions.
     2346    IMGUI_API void              GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);  // 1 byte per-pixel
     2347    IMGUI_API void              GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL);  // 4 bytes-per-pixel
     2348    bool                        IsBuilt() const             { return Fonts.Size > 0 && (TexPixelsAlpha8 != NULL || TexPixelsRGBA32 != NULL); }
     2349    void                        SetTexID(ImTextureID id)    { TexID = id; }
     2350
     2351    //-------------------------------------------
     2352    // Glyph Ranges
     2353    //-------------------------------------------
     2354
     2355    // Helpers to retrieve list of common Unicode ranges (2 value per range, values are inclusive, zero-terminated list)
     2356    // NB: Make sure that your string are UTF-8 and NOT in your local code page. In C++11, you can create UTF-8 string literal using the u8"Hello world" syntax. See FAQ for details.
     2357    // NB: Consider using ImFontGlyphRangesBuilder to build glyph ranges from textual data.
     2358    IMGUI_API const ImWchar*    GetGlyphRangesDefault();                // Basic Latin, Extended Latin
     2359    IMGUI_API const ImWchar*    GetGlyphRangesKorean();                 // Default + Korean characters
     2360    IMGUI_API const ImWchar*    GetGlyphRangesJapanese();               // Default + Hiragana, Katakana, Half-Width, Selection of 1946 Ideographs
     2361    IMGUI_API const ImWchar*    GetGlyphRangesChineseFull();            // Default + Half-Width + Japanese Hiragana/Katakana + full set of about 21000 CJK Unified Ideographs
     2362    IMGUI_API const ImWchar*    GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese
     2363    IMGUI_API const ImWchar*    GetGlyphRangesCyrillic();               // Default + about 400 Cyrillic characters
     2364    IMGUI_API const ImWchar*    GetGlyphRangesThai();                   // Default + Thai characters
     2365    IMGUI_API const ImWchar*    GetGlyphRangesVietnamese();             // Default + Vietnamese characters
     2366
     2367    //-------------------------------------------
     2368    // [BETA] Custom Rectangles/Glyphs API
     2369    //-------------------------------------------
     2370
     2371    // You can request arbitrary rectangles to be packed into the atlas, for your own purposes.
     2372    // After calling Build(), you can query the rectangle position and render your pixels.
     2373    // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point),
     2374    // so you can render e.g. custom colorful icons and use them as regular glyphs.
     2375    // Read docs/FONTS.md for more details about using colorful icons.
     2376    // Note: this API may be redesigned later in order to support multi-monitor varying DPI settings.
     2377    IMGUI_API int               AddCustomRectRegular(int width, int height);
     2378    IMGUI_API int               AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0, 0));
     2379    ImFontAtlasCustomRect*      GetCustomRectByIndex(int index) { IM_ASSERT(index >= 0); return &CustomRects[index]; }
     2380
     2381    // [Internal]
     2382    IMGUI_API void              CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const;
     2383    IMGUI_API bool              GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
     2384
     2385    //-------------------------------------------
     2386    // Members
     2387    //-------------------------------------------
     2388
     2389    bool                        Locked;             // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert.
     2390    ImFontAtlasFlags            Flags;              // Build flags (see ImFontAtlasFlags_)
     2391    ImTextureID                 TexID;              // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.
     2392    int                         TexDesiredWidth;    // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
     2393    int                         TexGlyphPadding;    // Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0.
     2394
     2395    // [Internal]
     2396    // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.
     2397    unsigned char*              TexPixelsAlpha8;    // 1 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight
     2398    unsigned int*               TexPixelsRGBA32;    // 4 component per pixel, each component is unsigned 8-bit. Total size = TexWidth * TexHeight * 4
     2399    int                         TexWidth;           // Texture width calculated during Build().
     2400    int                         TexHeight;          // Texture height calculated during Build().
     2401    ImVec2                      TexUvScale;         // = (1.0f/TexWidth, 1.0f/TexHeight)
     2402    ImVec2                      TexUvWhitePixel;    // Texture coordinates to a white pixel
     2403    ImVector<ImFont*>           Fonts;              // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font.
     2404    ImVector<ImFontAtlasCustomRect> CustomRects;    // Rectangles for packing custom texture data into the atlas.
     2405    ImVector<ImFontConfig>      ConfigData;         // Configuration data
     2406    ImVec4                      TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1];  // UVs for baked anti-aliased lines
     2407
     2408    // [Internal] Packing data
     2409    int                         PackIdMouseCursors; // Custom texture rectangle ID for white pixel and mouse cursors
     2410    int                         PackIdLines;        // Custom texture rectangle ID for baked anti-aliased lines
     2411
     2412#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     2413    typedef ImFontAtlasCustomRect    CustomRect;         // OBSOLETED in 1.72+
     2414    typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
     2415#endif
    17952416};
    17962417
     
    17992420struct ImFont
    18002421{
    1801    // Members: Hot ~62/78 bytes
    1802    float                       FontSize;           // <user set>   // Height of characters, set during loading (don't change after loading)
    1803    float                       Scale;              // = 1.f        // Base font scale, multiplied by the per-window font scale which you can adjust with SetFontScale()
    1804    ImVec2                      DisplayOffset;      // = (0.f,0.f)  // Offset font rendering by xx pixels
    1805    ImVector<ImFontGlyph>       Glyphs;             //              // All glyphs.
    1806    ImVector<float>             IndexAdvanceX;      //              // Sparse. Glyphs->AdvanceX in a directly indexable way (more cache-friendly, for CalcTextSize functions which are often bottleneck in large UI).
    1807    ImVector<unsigned short>    IndexLookup;        //              // Sparse. Index glyphs by Unicode code-point.
    1808    const ImFontGlyph*          FallbackGlyph;      // == FindGlyph(FontFallbackChar)
    1809    float                       FallbackAdvanceX;   // == FallbackGlyph->AdvanceX
    1810    ImWchar                     FallbackChar;       // = '?'        // Replacement glyph if one isn't found. Only set via SetFallbackChar()
    1811 
    1812                                                    // Members: Cold ~18/26 bytes
    1813    short                       ConfigDataCount;    // ~ 1          // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont.
    1814    ImFontConfig*               ConfigData;         //              // Pointer within ContainerAtlas->ConfigData
    1815    ImFontAtlas*                ContainerAtlas;     //              // What we has been loaded into
    1816    float                       Ascent, Descent;    //              // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]
    1817    bool                        DirtyLookupTables;
    1818    int                         MetricsTotalSurface;//              // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
    1819 
    1820                                                    // Methods
    1821    IMGUI_API ImFont();
    1822    IMGUI_API ~ImFont();
    1823    IMGUI_API void              ClearOutputData();
    1824    IMGUI_API void              BuildLookupTable();
    1825    IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const;
    1826    IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const;
    1827    IMGUI_API void              SetFallbackChar(ImWchar c);
    1828    float                       GetCharAdvance(ImWchar c) const { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; }
    1829    bool                        IsLoaded() const { return ContainerAtlas != NULL; }
    1830    const char*                 GetDebugName() const { return ConfigData ? ConfigData->Name : "<unknown>"; }
    1831 
    1832    // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.
    1833    // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable.
    1834    IMGUI_API ImVec2            CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8
    1835    IMGUI_API const char*       CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const;
    1836    IMGUI_API void              RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const;
    1837    IMGUI_API void              RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const;
    1838 
    1839    // [Internal]
    1840    IMGUI_API void              GrowIndex(int new_size);
    1841    IMGUI_API void              AddGlyph(ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
    1842    IMGUI_API void              AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
    1843 
    1844 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
    1845    typedef ImFontGlyph Glyph; // OBSOLETE 1.52+
    1846 #endif
     2422    // Members: Hot ~20/24 bytes (for CalcTextSize)
     2423    ImVector<float>             IndexAdvanceX;      // 12-16 // out //            // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI).
     2424    float                       FallbackAdvanceX;   // 4     // out // = FallbackGlyph->AdvanceX
     2425    float                       FontSize;           // 4     // in  //            // Height of characters/line, set during loading (don't change after loading)
     2426
     2427    // Members: Hot ~28/40 bytes (for CalcTextSize + render loop)
     2428    ImVector<ImWchar>           IndexLookup;        // 12-16 // out //            // Sparse. Index glyphs by Unicode code-point.
     2429    ImVector<ImFontGlyph>       Glyphs;             // 12-16 // out //            // All glyphs.
     2430    const ImFontGlyph*          FallbackGlyph;      // 4-8   // out // = FindGlyph(FontFallbackChar)
     2431
     2432    // Members: Cold ~32/40 bytes
     2433    ImFontAtlas*                ContainerAtlas;     // 4-8   // out //            // What we has been loaded into
     2434    const ImFontConfig*         ConfigData;         // 4-8   // in  //            // Pointer within ContainerAtlas->ConfigData
     2435    short                       ConfigDataCount;    // 2     // in  // ~ 1        // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont.
     2436    ImWchar                     FallbackChar;       // 2     // in  // = '?'      // Replacement character if a glyph isn't found. Only set via SetFallbackChar()
     2437    ImWchar                     EllipsisChar;       // 2     // out // = -1       // Character used for ellipsis rendering.
     2438    bool                        DirtyLookupTables;  // 1     // out //
     2439    float                       Scale;              // 4     // in  // = 1.f      // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
     2440    float                       Ascent, Descent;    // 4+4   // out //            // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]
     2441    int                         MetricsTotalSurface;// 4     // out //            // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
     2442    ImU8                        Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints.
     2443
     2444    // Methods
     2445    IMGUI_API ImFont();
     2446    IMGUI_API ~ImFont();
     2447    IMGUI_API const ImFontGlyph*FindGlyph(ImWchar c) const;
     2448    IMGUI_API const ImFontGlyph*FindGlyphNoFallback(ImWchar c) const;
     2449    float                       GetCharAdvance(ImWchar c) const     { return ((int)c < IndexAdvanceX.Size) ? IndexAdvanceX[(int)c] : FallbackAdvanceX; }
     2450    bool                        IsLoaded() const                    { return ContainerAtlas != NULL; }
     2451    const char*                 GetDebugName() const                { return ConfigData ? ConfigData->Name : "<unknown>"; }
     2452
     2453    // 'max_width' stops rendering after a certain width (could be turned into a 2d size). FLT_MAX to disable.
     2454    // 'wrap_width' enable automatic word-wrapping across multiple lines to fit into given width. 0.0f to disable.
     2455    IMGUI_API ImVec2            CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end = NULL, const char** remaining = NULL) const; // utf8
     2456    IMGUI_API const char*       CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const;
     2457    IMGUI_API void              RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const;
     2458    IMGUI_API void              RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width = 0.0f, bool cpu_fine_clip = false) const;
     2459
     2460    // [Internal] Don't use!
     2461    IMGUI_API void              BuildLookupTable();
     2462    IMGUI_API void              ClearOutputData();
     2463    IMGUI_API void              GrowIndex(int new_size);
     2464    IMGUI_API void              AddGlyph(const ImFontConfig* src_cfg, ImWchar c, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x);
     2465    IMGUI_API void              AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst = true); // Makes 'dst' character/glyph points to 'src' character/glyph. Currently needs to be called AFTER fonts have been built.
     2466    IMGUI_API void              SetGlyphVisible(ImWchar c, bool visible);
     2467    IMGUI_API void              SetFallbackChar(ImWchar c);
     2468    IMGUI_API bool              IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last);
    18472469};
    18482470
    18492471#if defined(__clang__)
    18502472#pragma clang diagnostic pop
     2473#elif defined(__GNUC__)
     2474#pragma GCC diagnostic pop
    18512475#endif
    18522476
     
    18552479#include "imgui_user.h"
    18562480#endif
     2481
     2482#endif // #ifndef IMGUI_DISABLE
  • IMGUI/imgui_demo.cpp

    r78c3045 re66fd66  
    1 // dear imgui, v1.61 WIP
     1// dear imgui, v1.79
    22// (demo code)
    33
    4 // Message to the person tempted to delete this file when integrating ImGui into their code base:
    5 // Don't do it! Do NOT remove this file from your project! It is useful reference code that you and other users will want to refer to.
     4// Help:
     5// - Read FAQ at http://dearimgui.org/faq
     6// - Newcomers, read 'Programmer guide' in imgui.cpp 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 more details, documentation and comments.
     9// Get latest version at https://github.com/ocornut/imgui
     10
     11// Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
     12// Do NOT remove this file from your project! Think again! It is the most useful reference code that you and other
     13// coders will want to refer to and call. Have the ImGui::ShowDemoWindow() function wired in an always-available
     14// debug menu of your game/app! Removing this file from your project is hindering access to documentation for everyone
     15// in your team, likely leading you to poorer usage of the library.
    616// Everything in this file will be stripped out by the linker if you don't call ImGui::ShowDemoWindow().
    7 // During development, you can call ImGui::ShowDemoWindow() in your code to learn about various features of ImGui. Have it wired in a debug menu!
    8 // Removing this file from your project is hindering access to documentation for everyone in your team, likely leading you to poorer usage of the library.
    9 // Note that you can #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h for the same effect.
    10 // If you want to link core ImGui in your final builds but not those demo windows, #define IMGUI_DISABLE_DEMO_WINDOWS in imconfig.h and those functions will be empty.
    11 // In other situation, when you have ImGui available you probably want this to be available for reference and execution.
     17// If you want to link core Dear ImGui in your shipped builds but want a thorough guarantee that the demo will not be
     18// linked, you can setup your imconfig.h with #define IMGUI_DISABLE_DEMO_WINDOWS and those functions will be empty.
     19// In other situation, whenever you have Dear ImGui available you probably want this to be available for reference.
    1220// Thank you,
    13 // -Your beloved friend, imgui_demo.cpp (that you won't delete)
    14 
    15 // Message to beginner C/C++ programmers. About the meaning of 'static': in this demo code, we frequently we use 'static' variables inside functions.
    16 // We do this as a way to gather code and data in the same place, just to make the demo code faster to read, faster to write, and use less code.
    17 // A static variable persist across calls, so it is essentially like a global variable but declared inside the scope of the function.
    18 // It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant or used in threads.
    19 // This might be a pattern you occasionally want to use in your code, but most of the real data you would be editing is likely to be stored outside your function.
     21// -Your beloved friend, imgui_demo.cpp (which you won't delete)
     22
     23// Message to beginner C/C++ programmers about the meaning of the 'static' keyword:
     24// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls,
     25// so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to
     26// gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller
     27// in size. It also happens to be a convenient way of storing simple UI related information as long as your function
     28// doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code,
     29// but most of the real data you would be editing is likely going to be stored outside your functions.
     30
     31// The Demo code in this file is designed to be easy to copy-and-paste in into your application!
     32// Because of this:
     33// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
     34// - We try to declare static variables in the local scope, as close as possible to the code using them.
     35// - We never use any of the helpers/facilities used internally by Dear ImGui, unless available in the public API.
     36// - We never use maths operators on ImVec2/ImVec4. For our other sources files we use them, and they are provided
     37//   by imgui_internal.h using the IMGUI_DEFINE_MATH_OPERATORS define. For your own sources file they are optional
     38//   and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h.
     39//   Because we can't assume anything about your support of maths operators, we cannot use them in imgui_demo.cpp.
     40
     41/*
     42
     43Index of this file:
     44
     45// [SECTION] Forward Declarations, Helpers
     46// [SECTION] Demo Window / ShowDemoWindow()
     47// [SECTION] About Window / ShowAboutWindow()
     48// [SECTION] Style Editor / ShowStyleEditor()
     49// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
     50// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
     51// [SECTION] Example App: Debug Log / ShowExampleAppLog()
     52// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
     53// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
     54// [SECTION] Example App: Long Text / ShowExampleAppLongText()
     55// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
     56// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
     57// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay()
     58// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
     59// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
     60// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
     61
     62*/
    2063
    2164#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
     
    2467
    2568#include "imgui.h"
    26 #include <ctype.h>          // toupper, isprint
     69#ifndef IMGUI_DISABLE
     70
     71#include <ctype.h>          // toupper
     72#include <limits.h>         // INT_MIN, INT_MAX
    2773#include <math.h>           // sqrtf, powf, cosf, sinf, floorf, ceilf
    2874#include <stdio.h>          // vsnprintf, sscanf, printf
     
    3480#endif
    3581
     82// Visual Studio warnings
    3683#ifdef _MSC_VER
    3784#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
    38 #define snprintf _snprintf
    3985#endif
    40 #ifdef __clang__
    41 #pragma clang diagnostic ignored "-Wold-style-cast"             // warning : use of old-style cast                              // yes, they are more terse.
    42 #pragma clang diagnostic ignored "-Wdeprecated-declarations"    // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code)
    43 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"   // warning : cast to 'void *' from smaller integer type 'int'
    44 #pragma clang diagnostic ignored "-Wformat-security"            // warning : warning: format string is not a string literal
    45 #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.
    46 #if __has_warning("-Wreserved-id-macro")
    47 #pragma clang diagnostic ignored "-Wreserved-id-macro"          // warning : macro name is a reserved identifier                //
     86
     87// Clang/GCC warnings with -Weverything
     88#if defined(__clang__)
     89#if __has_warning("-Wunknown-warning-option")
     90#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!
    4891#endif
     92#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
     93#pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                           // yes, they are more terse.
     94#pragma clang diagnostic ignored "-Wdeprecated-declarations"        // warning: 'xx' is deprecated: The POSIX name for this..   // for strdup used in demo code (so user can copy & paste the code)
     95#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning: cast to 'void *' from smaller integer type
     96#pragma clang diagnostic ignored "-Wformat-security"                // warning: format string is not a string literal
     97#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.
     98#pragma clang diagnostic ignored "-Wunused-macros"                  // warning: macro is not used                               // we define snprintf/vsnprintf on Windows so they are available, but not always used.
     99#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                   // some standard header variations use #define NULL 0
     100#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.
     101#pragma clang diagnostic ignored "-Wreserved-id-macro"              // warning: macro name is a reserved identifier
     102#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
    49103#elif defined(__GNUC__)
    50 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"          // warning: cast to pointer from integer of different size
    51 #pragma GCC diagnostic ignored "-Wformat-security"              // warning : format string is not a string literal (potentially insecure)
    52 #pragma GCC diagnostic ignored "-Wdouble-promotion"             // warning: implicit conversion from 'float' to 'double' when passing argument to function
    53 #pragma GCC diagnostic ignored "-Wconversion"                   // warning: conversion to 'xxxx' from 'xxxx' may alter its value
    54 #if (__GNUC__ >= 6)
    55 #pragma GCC diagnostic ignored "-Wmisleading-indentation"       // warning: this 'if' clause does not guard this statement      // GCC 6.0+ only. See #883 on GitHub.
     104#pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
     105#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"      // warning: cast to pointer from integer of different size
     106#pragma GCC diagnostic ignored "-Wformat-security"          // warning: format string is not a string literal (potentially insecure)
     107#pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
     108#pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
     109#pragma GCC diagnostic ignored "-Wmisleading-indentation"   // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement      // GCC 6.0+ only. See #883 on GitHub.
    56110#endif
     111
     112// Play it nice with Windows users (Update: May 2018, Notepad now supports Unix-style carriage returns!)
     113#ifdef _WIN32
     114#define IM_NEWLINE  "\r\n"
     115#else
     116#define IM_NEWLINE  "\n"
    57117#endif
    58118
    59 // Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n.
    60 #ifdef _WIN32
    61 #define IM_NEWLINE "\r\n"
    62 #else
    63 #define IM_NEWLINE "\n"
     119// Helpers
     120#if defined(_MSC_VER) && !defined(snprintf)
     121#define snprintf    _snprintf
    64122#endif
    65 
    66 #define IM_MAX(_A,_B)       (((_A) >= (_B)) ? (_A) : (_B))
     123#if defined(_MSC_VER) && !defined(vsnprintf)
     124#define vsnprintf   _vsnprintf
     125#endif
     126
     127// Helpers macros
     128// We normally try to not use many helpers in imgui_demo.cpp in order to make code easier to copy and paste,
     129// but making an exception here as those are largely simplifying code...
     130// In other imgui sources we can use nicer internal functions from imgui_internal.h (ImMin/ImMax) but not in the demo.
     131#define IM_MIN(A, B)            (((A) < (B)) ? (A) : (B))
     132#define IM_MAX(A, B)            (((A) >= (B)) ? (A) : (B))
     133#define IM_CLAMP(V, MN, MX)     ((V) < (MN) ? (MN) : (V) > (MX) ? (MX) : (V))
    67134
    68135//-----------------------------------------------------------------------------
    69 // DEMO CODE
     136// [SECTION] Forward Declarations, Helpers
    70137//-----------------------------------------------------------------------------
    71138
    72 #if !defined(IMGUI_DISABLE_OBSOLETE_FUNCTIONS) && defined(IMGUI_DISABLE_TEST_WINDOWS) && !defined(IMGUI_DISABLE_DEMO_WINDOWS)   // Obsolete name since 1.53, TEST->DEMO
    73 #define IMGUI_DISABLE_DEMO_WINDOWS
    74 #endif
    75 
    76139#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
    77140
     141// Forward Declarations
     142static void ShowExampleAppDocuments(bool* p_open);
     143static void ShowExampleAppMainMenuBar();
    78144static void ShowExampleAppConsole(bool* p_open);
    79145static void ShowExampleAppLog(bool* p_open);
     
    83149static void ShowExampleAppAutoResize(bool* p_open);
    84150static void ShowExampleAppConstrainedResize(bool* p_open);
    85 static void ShowExampleAppFixedOverlay(bool* p_open);
     151static void ShowExampleAppSimpleOverlay(bool* p_open);
    86152static void ShowExampleAppWindowTitles(bool* p_open);
    87153static void ShowExampleAppCustomRendering(bool* p_open);
    88 static void ShowExampleAppMainMenuBar();
    89154static void ShowExampleMenuFile();
    90155
    91 static void ShowHelpMarker(const char* desc)
     156// Helper to display a little (?) mark which shows a tooltip when hovered.
     157// In your own code you may want to display an actual icon if you are using a merged icon fonts (see docs/FONTS.md)
     158static void HelpMarker(const char* desc)
    92159{
    93    ImGui::TextDisabled("(?)");
    94    if (ImGui::IsItemHovered())
    95    {
    96       ImGui::BeginTooltip();
    97       ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
    98       ImGui::TextUnformatted(desc);
    99       ImGui::PopTextWrapPos();
    100       ImGui::EndTooltip();
    101    }
     160    ImGui::TextDisabled("(?)");
     161    if (ImGui::IsItemHovered())
     162    {
     163        ImGui::BeginTooltip();
     164        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
     165        ImGui::TextUnformatted(desc);
     166        ImGui::PopTextWrapPos();
     167        ImGui::EndTooltip();
     168    }
    102169}
    103170
     171// Helper to display basic user controls.
    104172void ImGui::ShowUserGuide()
    105173{
    106    ImGui::BulletText("Double-click on title bar to collapse window.");
    107    ImGui::BulletText("Click and drag on lower right corner to resize window\n(double-click to auto fit window to its contents).");
    108    ImGui::BulletText("Click and drag on any empty space to move window.");
    109    ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
    110    ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
    111    if (ImGui::GetIO().FontAllowUserScaling)
    112       ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
    113    ImGui::BulletText("Mouse Wheel to scroll.");
    114    ImGui::BulletText("While editing text:\n");
    115    ImGui::Indent();
    116    ImGui::BulletText("Hold SHIFT or use mouse to select text.");
    117    ImGui::BulletText("CTRL+Left/Right to word jump.");
    118    ImGui::BulletText("CTRL+A or double-click to select all.");
    119    ImGui::BulletText("CTRL+X,CTRL+C,CTRL+V to use clipboard.");
    120    ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
    121    ImGui::BulletText("ESCAPE to revert.");
    122    ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
    123    ImGui::Unindent();
     174    ImGuiIO& io = ImGui::GetIO();
     175    ImGui::BulletText("Double-click on title bar to collapse window.");
     176    ImGui::BulletText(
     177        "Click and drag on lower corner to resize window\n"
     178        "(double-click to auto fit window to its contents).");
     179    ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
     180    ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
     181    if (io.FontAllowUserScaling)
     182        ImGui::BulletText("CTRL+Mouse Wheel to zoom window contents.");
     183    ImGui::BulletText("While inputing text:\n");
     184    ImGui::Indent();
     185    ImGui::BulletText("CTRL+Left/Right to word jump.");
     186    ImGui::BulletText("CTRL+A or double-click to select all.");
     187    ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
     188    ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
     189    ImGui::BulletText("ESCAPE to revert.");
     190    ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
     191    ImGui::Unindent();
     192    ImGui::BulletText("With keyboard navigation enabled:");
     193    ImGui::Indent();
     194    ImGui::BulletText("Arrow keys to navigate.");
     195    ImGui::BulletText("Space to activate a widget.");
     196    ImGui::BulletText("Return to input text into a widget.");
     197    ImGui::BulletText("Escape to deactivate a widget, close popup, exit child window.");
     198    ImGui::BulletText("Alt to jump to the menu layer of a window.");
     199    ImGui::BulletText("CTRL+Tab to select a window.");
     200    ImGui::Unindent();
    124201}
    125202
    126 // Demonstrate most ImGui features (big function!)
     203//-----------------------------------------------------------------------------
     204// [SECTION] Demo Window / ShowDemoWindow()
     205//-----------------------------------------------------------------------------
     206// - ShowDemoWindowWidgets()
     207// - ShowDemoWindowLayout()
     208// - ShowDemoWindowPopups()
     209// - ShowDemoWindowColumns()
     210// - ShowDemoWindowMisc()
     211//-----------------------------------------------------------------------------
     212
     213// We split the contents of the big ShowDemoWindow() function into smaller functions
     214// (because the link time of very large functions grow non-linearly)
     215static void ShowDemoWindowWidgets();
     216static void ShowDemoWindowLayout();
     217static void ShowDemoWindowPopups();
     218static void ShowDemoWindowColumns();
     219static void ShowDemoWindowMisc();
     220
     221// Demonstrate most Dear ImGui features (this is big function!)
     222// You may execute this function to experiment with the UI and understand what it does.
     223// You may then search for keywords in the code when you are interested by a specific feature.
    127224void ImGui::ShowDemoWindow(bool* p_open)
    128225{
    129    // Examples apps
    130    static bool show_app_main_menu_bar = false;
    131    static bool show_app_console = false;
    132    static bool show_app_log = false;
    133    static bool show_app_layout = false;
    134    static bool show_app_property_editor = false;
    135    static bool show_app_long_text = false;
    136    static bool show_app_auto_resize = false;
    137    static bool show_app_constrained_resize = false;
    138    static bool show_app_fixed_overlay = false;
    139    static bool show_app_window_titles = false;
    140    static bool show_app_custom_rendering = false;
    141    static bool show_app_style_editor = false;
    142 
    143    static bool show_app_metrics = false;
    144    static bool show_app_about = false;
    145 
    146    if (show_app_main_menu_bar)       ShowExampleAppMainMenuBar();
    147    if (show_app_console)             ShowExampleAppConsole(&show_app_console);
    148    if (show_app_log)                 ShowExampleAppLog(&show_app_log);
    149    if (show_app_layout)              ShowExampleAppLayout(&show_app_layout);
    150    if (show_app_property_editor)     ShowExampleAppPropertyEditor(&show_app_property_editor);
    151    if (show_app_long_text)           ShowExampleAppLongText(&show_app_long_text);
    152    if (show_app_auto_resize)         ShowExampleAppAutoResize(&show_app_auto_resize);
    153    if (show_app_constrained_resize)  ShowExampleAppConstrainedResize(&show_app_constrained_resize);
    154    if (show_app_fixed_overlay)       ShowExampleAppFixedOverlay(&show_app_fixed_overlay);
    155    if (show_app_window_titles)       ShowExampleAppWindowTitles(&show_app_window_titles);
    156    if (show_app_custom_rendering)    ShowExampleAppCustomRendering(&show_app_custom_rendering);
    157 
    158    if (show_app_metrics) { ImGui::ShowMetricsWindow(&show_app_metrics); }
    159    if (show_app_style_editor) { ImGui::Begin("Style Editor", &show_app_style_editor); ImGui::ShowStyleEditor(); ImGui::End(); }
    160    if (show_app_about)
    161    {
    162       ImGui::Begin("About Dear ImGui", &show_app_about, ImGuiWindowFlags_AlwaysAutoResize);
    163       ImGui::Text("Dear ImGui, %s", ImGui::GetVersion());
    164       ImGui::Separator();
    165       ImGui::Text("By Omar Cornut and all dear imgui contributors.");
    166       ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
    167       ImGui::End();
    168    }
    169 
    170    static bool no_titlebar = false;
    171    static bool no_scrollbar = false;
    172    static bool no_menu = false;
    173    static bool no_move = false;
    174    static bool no_resize = false;
    175    static bool no_collapse = false;
    176    static bool no_close = false;
    177    static bool no_nav = false;
    178 
    179    // Demonstrate the various window flags. Typically you would just use the default.
    180    ImGuiWindowFlags window_flags = 0;
    181    if (no_titlebar)  window_flags |= ImGuiWindowFlags_NoTitleBar;
    182    if (no_scrollbar) window_flags |= ImGuiWindowFlags_NoScrollbar;
    183    if (!no_menu)     window_flags |= ImGuiWindowFlags_MenuBar;
    184    if (no_move)      window_flags |= ImGuiWindowFlags_NoMove;
    185    if (no_resize)    window_flags |= ImGuiWindowFlags_NoResize;
    186    if (no_collapse)  window_flags |= ImGuiWindowFlags_NoCollapse;
    187    if (no_nav)       window_flags |= ImGuiWindowFlags_NoNav;
    188    if (no_close)     p_open = NULL; // Don't pass our bool* to Begin
    189 
    190    ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
    191    if (!ImGui::Begin("ImGui Demo", p_open, window_flags))
    192    {
    193       // Early out if the window is collapsed, as an optimization.
    194       ImGui::End();
    195       return;
    196    }
    197 
    198    //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f);    // 2/3 of the space for widget and 1/3 for labels
    199    ImGui::PushItemWidth(-140);                                 // Right align, keep 140 pixels for labels
    200 
    201    ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION);
    202 
    203    // Menu
    204    if (ImGui::BeginMenuBar())
    205    {
    206       if (ImGui::BeginMenu("Menu"))
    207       {
    208          ShowExampleMenuFile();
    209          ImGui::EndMenu();
    210       }
    211       if (ImGui::BeginMenu("Examples"))
    212       {
    213          ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
    214          ImGui::MenuItem("Console", NULL, &show_app_console);
    215          ImGui::MenuItem("Log", NULL, &show_app_log);
    216          ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
    217          ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
    218          ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
    219          ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
    220          ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
    221          ImGui::MenuItem("Simple overlay", NULL, &show_app_fixed_overlay);
    222          ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
    223          ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
    224          ImGui::EndMenu();
    225       }
    226       if (ImGui::BeginMenu("Help"))
    227       {
    228          ImGui::MenuItem("Metrics", NULL, &show_app_metrics);
    229          ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
    230          ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
    231          ImGui::EndMenu();
    232       }
    233       ImGui::EndMenuBar();
    234    }
    235 
    236    ImGui::Spacing();
    237    if (ImGui::CollapsingHeader("Help"))
    238    {
    239       ImGui::TextWrapped("This window is being created by the ShowDemoWindow() function. Please refer to the code in imgui_demo.cpp for reference.\n\n");
    240       ImGui::Text("USER GUIDE:");
    241       ImGui::ShowUserGuide();
    242    }
    243 
    244    if (ImGui::CollapsingHeader("Window options"))
    245    {
    246       ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150);
    247       ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300);
    248       ImGui::Checkbox("No menu", &no_menu);
    249       ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150);
    250       ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300);
    251       ImGui::Checkbox("No collapse", &no_collapse);
    252       ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150);
    253       ImGui::Checkbox("No nav", &no_nav);
    254 
    255       if (ImGui::TreeNode("Style"))
    256       {
    257          ImGui::ShowStyleEditor();
    258          ImGui::TreePop();
    259       }
    260 
    261       if (ImGui::TreeNode("Capture/Logging"))
    262       {
    263          ImGui::TextWrapped("The logging API redirects all text output so you can easily capture the content of a window or a block. Tree nodes can be automatically expanded. You can also call ImGui::LogText() to output directly to the log without a visual output.");
    264          ImGui::LogButtons();
    265          ImGui::TreePop();
    266       }
    267    }
    268 
    269    if (ImGui::CollapsingHeader("Widgets"))
    270    {
    271       if (ImGui::TreeNode("Basic"))
    272       {
    273          static int clicked = 0;
    274          if (ImGui::Button("Button"))
     226    // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
     227    // Most ImGui functions would normally just crash if the context is missing.
     228    IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!");
     229
     230    // Examples Apps (accessible from the "Examples" menu)
     231    static bool show_app_main_menu_bar = false;
     232    static bool show_app_documents = false;
     233    static bool show_app_console = false;
     234    static bool show_app_log = false;
     235    static bool show_app_layout = false;
     236    static bool show_app_property_editor = false;
     237    static bool show_app_long_text = false;
     238    static bool show_app_auto_resize = false;
     239    static bool show_app_constrained_resize = false;
     240    static bool show_app_simple_overlay = false;
     241    static bool show_app_window_titles = false;
     242    static bool show_app_custom_rendering = false;
     243
     244    if (show_app_main_menu_bar)       ShowExampleAppMainMenuBar();
     245    if (show_app_documents)           ShowExampleAppDocuments(&show_app_documents);
     246
     247    if (show_app_console)             ShowExampleAppConsole(&show_app_console);
     248    if (show_app_log)                 ShowExampleAppLog(&show_app_log);
     249    if (show_app_layout)              ShowExampleAppLayout(&show_app_layout);
     250    if (show_app_property_editor)     ShowExampleAppPropertyEditor(&show_app_property_editor);
     251    if (show_app_long_text)           ShowExampleAppLongText(&show_app_long_text);
     252    if (show_app_auto_resize)         ShowExampleAppAutoResize(&show_app_auto_resize);
     253    if (show_app_constrained_resize)  ShowExampleAppConstrainedResize(&show_app_constrained_resize);
     254    if (show_app_simple_overlay)      ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
     255    if (show_app_window_titles)       ShowExampleAppWindowTitles(&show_app_window_titles);
     256    if (show_app_custom_rendering)    ShowExampleAppCustomRendering(&show_app_custom_rendering);
     257
     258    // Dear ImGui Apps (accessible from the "Tools" menu)
     259    static bool show_app_metrics = false;
     260    static bool show_app_style_editor = false;
     261    static bool show_app_about = false;
     262
     263    if (show_app_metrics)       { ImGui::ShowMetricsWindow(&show_app_metrics); }
     264    if (show_app_about)         { ImGui::ShowAboutWindow(&show_app_about); }
     265    if (show_app_style_editor)
     266    {
     267        ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor);
     268        ImGui::ShowStyleEditor();
     269        ImGui::End();
     270    }
     271
     272    // Demonstrate the various window flags. Typically you would just use the default!
     273    static bool no_titlebar = false;
     274    static bool no_scrollbar = false;
     275    static bool no_menu = false;
     276    static bool no_move = false;
     277    static bool no_resize = false;
     278    static bool no_collapse = false;
     279    static bool no_close = false;
     280    static bool no_nav = false;
     281    static bool no_background = false;
     282    static bool no_bring_to_front = false;
     283
     284    ImGuiWindowFlags window_flags = 0;
     285    if (no_titlebar)        window_flags |= ImGuiWindowFlags_NoTitleBar;
     286    if (no_scrollbar)       window_flags |= ImGuiWindowFlags_NoScrollbar;
     287    if (!no_menu)           window_flags |= ImGuiWindowFlags_MenuBar;
     288    if (no_move)            window_flags |= ImGuiWindowFlags_NoMove;
     289    if (no_resize)          window_flags |= ImGuiWindowFlags_NoResize;
     290    if (no_collapse)        window_flags |= ImGuiWindowFlags_NoCollapse;
     291    if (no_nav)             window_flags |= ImGuiWindowFlags_NoNav;
     292    if (no_background)      window_flags |= ImGuiWindowFlags_NoBackground;
     293    if (no_bring_to_front)  window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus;
     294    if (no_close)           p_open = NULL; // Don't pass our bool* to Begin
     295
     296    // We specify a default position/size in case there's no data in the .ini file.
     297    // We only do it to make the demo applications a little more welcoming, but typically this isn't required.
     298    ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver);
     299    ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
     300
     301    // Main body of the Demo window starts here.
     302    if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
     303    {
     304        // Early out if the window is collapsed, as an optimization.
     305        ImGui::End();
     306        return;
     307    }
     308
     309    // Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
     310
     311    // e.g. Use 2/3 of the space for widgets and 1/3 for labels (default)
     312    //ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.65f);
     313
     314    // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
     315    ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
     316
     317    // Menu Bar
     318    if (ImGui::BeginMenuBar())
     319    {
     320        if (ImGui::BeginMenu("Menu"))
     321        {
     322            ShowExampleMenuFile();
     323            ImGui::EndMenu();
     324        }
     325        if (ImGui::BeginMenu("Examples"))
     326        {
     327            ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
     328            ImGui::MenuItem("Console", NULL, &show_app_console);
     329            ImGui::MenuItem("Log", NULL, &show_app_log);
     330            ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
     331            ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
     332            ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
     333            ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
     334            ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
     335            ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
     336            ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
     337            ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
     338            ImGui::MenuItem("Documents", NULL, &show_app_documents);
     339            ImGui::EndMenu();
     340        }
     341        if (ImGui::BeginMenu("Tools"))
     342        {
     343            ImGui::MenuItem("Metrics", NULL, &show_app_metrics);
     344            ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
     345            ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
     346            ImGui::EndMenu();
     347        }
     348        ImGui::EndMenuBar();
     349    }
     350
     351    ImGui::Text("dear imgui says hello. (%s)", IMGUI_VERSION);
     352    ImGui::Spacing();
     353
     354    if (ImGui::CollapsingHeader("Help"))
     355    {
     356        ImGui::Text("ABOUT THIS DEMO:");
     357        ImGui::BulletText("Sections below are demonstrating many aspects of the library.");
     358        ImGui::BulletText("The \"Examples\" menu above leads to more demo contents.");
     359        ImGui::BulletText("The \"Tools\" menu above gives access to: About Box, Style Editor,\n"
     360                          "and Metrics (general purpose Dear ImGui debugging tool).");
     361        ImGui::Separator();
     362
     363        ImGui::Text("PROGRAMMER GUIDE:");
     364        ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
     365        ImGui::BulletText("See comments in imgui.cpp.");
     366        ImGui::BulletText("See example applications in the examples/ folder.");
     367        ImGui::BulletText("Read the FAQ at http://www.dearimgui.org/faq/");
     368        ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
     369        ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
     370        ImGui::Separator();
     371
     372        ImGui::Text("USER GUIDE:");
     373        ImGui::ShowUserGuide();
     374    }
     375
     376    if (ImGui::CollapsingHeader("Configuration"))
     377    {
     378        ImGuiIO& io = ImGui::GetIO();
     379
     380        if (ImGui::TreeNode("Configuration##2"))
     381        {
     382            ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard",    (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
     383            ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad",     (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
     384            ImGui::SameLine(); HelpMarker("Required back-end to feed in gamepad inputs in io.NavInputs[] and set io.BackendFlags |= ImGuiBackendFlags_HasGamepad.\n\nRead instructions in imgui.cpp for details.");
     385            ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
     386            ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
     387            ImGui::CheckboxFlags("io.ConfigFlags: NoMouse",              (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouse);
     388
     389            // The "NoMouse" option above can get us stuck with a disable mouse! Provide an alternative way to fix it:
     390            if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
     391            {
     392                if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
     393                {
     394                    ImGui::SameLine();
     395                    ImGui::Text("<<PRESS SPACE TO DISABLE>>");
     396                }
     397                if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Space)))
     398                    io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
     399            }
     400            ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int*)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
     401            ImGui::SameLine(); HelpMarker("Instruct back-end to not alter mouse cursor shape and visibility.");
     402            ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
     403            ImGui::SameLine(); HelpMarker("Set to false to disable blinking cursor, for users who consider it distracting");
     404            ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
     405            ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback.");
     406            ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
     407            ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
     408            ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
     409            ImGui::Text("Also see Style->Rendering for rendering options.");
     410            ImGui::TreePop();
     411            ImGui::Separator();
     412        }
     413
     414        if (ImGui::TreeNode("Backend Flags"))
     415        {
     416            HelpMarker(
     417                "Those flags are set by the back-ends (imgui_impl_xxx files) to specify their capabilities.\n"
     418                "Here we expose then as read-only fields to avoid breaking interactions with your back-end.");
     419
     420            // Make a local copy to avoid modifying actual back-end flags.
     421            ImGuiBackendFlags backend_flags = io.BackendFlags;
     422            ImGui::CheckboxFlags("io.BackendFlags: HasGamepad",           (unsigned int*)&backend_flags, ImGuiBackendFlags_HasGamepad);
     423            ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors",      (unsigned int*)&backend_flags, ImGuiBackendFlags_HasMouseCursors);
     424            ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos",       (unsigned int*)&backend_flags, ImGuiBackendFlags_HasSetMousePos);
     425            ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", (unsigned int*)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset);
     426            ImGui::TreePop();
     427            ImGui::Separator();
     428        }
     429
     430        if (ImGui::TreeNode("Style"))
     431        {
     432            HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
     433            ImGui::ShowStyleEditor();
     434            ImGui::TreePop();
     435            ImGui::Separator();
     436        }
     437
     438        if (ImGui::TreeNode("Capture/Logging"))
     439        {
     440            HelpMarker(
     441                "The logging API redirects all text output so you can easily capture the content of "
     442                "a window or a block. Tree nodes can be automatically expanded.\n"
     443                "Try opening any of the contents below in this window and then click one of the \"Log To\" button.");
     444            ImGui::LogButtons();
     445
     446            HelpMarker("You can also call ImGui::LogText() to output directly to the log without a visual output.");
     447            if (ImGui::Button("Copy \"Hello, world!\" to clipboard"))
     448            {
     449                ImGui::LogToClipboard();
     450                ImGui::LogText("Hello, world!");
     451                ImGui::LogFinish();
     452            }
     453            ImGui::TreePop();
     454        }
     455    }
     456
     457    if (ImGui::CollapsingHeader("Window options"))
     458    {
     459        ImGui::Checkbox("No titlebar", &no_titlebar); ImGui::SameLine(150);
     460        ImGui::Checkbox("No scrollbar", &no_scrollbar); ImGui::SameLine(300);
     461        ImGui::Checkbox("No menu", &no_menu);
     462        ImGui::Checkbox("No move", &no_move); ImGui::SameLine(150);
     463        ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300);
     464        ImGui::Checkbox("No collapse", &no_collapse);
     465        ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150);
     466        ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300);
     467        ImGui::Checkbox("No background", &no_background);
     468        ImGui::Checkbox("No bring to front", &no_bring_to_front);
     469    }
     470
     471    // All demo contents
     472    ShowDemoWindowWidgets();
     473    ShowDemoWindowLayout();
     474    ShowDemoWindowPopups();
     475    ShowDemoWindowColumns();
     476    ShowDemoWindowMisc();
     477
     478    // End of ShowDemoWindow()
     479    ImGui::End();
     480}
     481
     482static void ShowDemoWindowWidgets()
     483{
     484    if (!ImGui::CollapsingHeader("Widgets"))
     485        return;
     486
     487    if (ImGui::TreeNode("Basic"))
     488    {
     489        static int clicked = 0;
     490        if (ImGui::Button("Button"))
    275491            clicked++;
    276          if (clicked & 1)
    277          {
     492        if (clicked & 1)
     493        {
    278494            ImGui::SameLine();
    279495            ImGui::Text("Thanks for clicking me!");
    280          }
    281 
    282          static bool check = true;
    283          ImGui::Checkbox("checkbox", &check);
    284 
    285          static int e = 0;
    286          ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
    287          ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
    288          ImGui::RadioButton("radio c", &e, 2);
    289 
    290          // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
    291          for (int i = 0; i < 7; i++)
    292          {
    293             if (i > 0) ImGui::SameLine();
     496        }
     497
     498        static bool check = true;
     499        ImGui::Checkbox("checkbox", &check);
     500
     501        static int e = 0;
     502        ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine();
     503        ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine();
     504        ImGui::RadioButton("radio c", &e, 2);
     505
     506        // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style.
     507        for (int i = 0; i < 7; i++)
     508        {
     509            if (i > 0)
     510                ImGui::SameLine();
    294511            ImGui::PushID(i);
    295512            ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i / 7.0f, 0.6f, 0.6f));
     
    299516            ImGui::PopStyleColor(3);
    300517            ImGui::PopID();
    301          }
    302 
    303          // Arrow buttons
    304          float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
    305          if (ImGui::ArrowButton("##left", ImGuiDir_Left)) {}
    306          ImGui::SameLine(0.0f, spacing);
    307          if (ImGui::ArrowButton("##left", ImGuiDir_Right)) {}
    308 
    309          ImGui::Text("Hover over me");
    310          if (ImGui::IsItemHovered())
     518        }
     519
     520        // Use AlignTextToFramePadding() to align text baseline to the baseline of framed widgets elements
     521        // (otherwise a Text+SameLine+Button sequence will have the text a little too high by default!)
     522        // See 'Demo->Layout->Text Baseline Alignment' for details.
     523        ImGui::AlignTextToFramePadding();
     524        ImGui::Text("Hold to repeat:");
     525        ImGui::SameLine();
     526
     527        // Arrow buttons with Repeater
     528        static int counter = 0;
     529        float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
     530        ImGui::PushButtonRepeat(true);
     531        if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
     532        ImGui::SameLine(0.0f, spacing);
     533        if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
     534        ImGui::PopButtonRepeat();
     535        ImGui::SameLine();
     536        ImGui::Text("%d", counter);
     537
     538        ImGui::Text("Hover over me");
     539        if (ImGui::IsItemHovered())
    311540            ImGui::SetTooltip("I am a tooltip");
    312541
    313          ImGui::SameLine();
    314          ImGui::Text("- or me");
    315          if (ImGui::IsItemHovered())
    316          {
     542        ImGui::SameLine();
     543        ImGui::Text("- or me");
     544        if (ImGui::IsItemHovered())
     545        {
    317546            ImGui::BeginTooltip();
    318547            ImGui::Text("I am a fancy tooltip");
     
    320549            ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
    321550            ImGui::EndTooltip();
    322          }
    323 
    324          ImGui::Separator();
    325 
    326          ImGui::LabelText("label", "Value");
    327 
    328          {
     551        }
     552
     553        ImGui::Separator();
     554
     555        ImGui::LabelText("label", "Value");
     556
     557        {
    329558            // Using the _simplified_ one-liner Combo() api here
    330             const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
     559            // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api.
     560            const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
    331561            static int item_current = 0;
    332562            ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
    333             ImGui::SameLine(); ShowHelpMarker("Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, and demonstration of various flags.\n");
    334          }
    335 
    336          {
     563            ImGui::SameLine(); HelpMarker(
     564                "Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, "
     565                "and demonstration of various flags.\n");
     566        }
     567
     568        {
     569            // To wire InputText() with std::string or any other custom string type,
     570            // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
    337571            static char str0[128] = "Hello, world!";
     572            ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
     573            ImGui::SameLine(); HelpMarker(
     574                "USER:\n"
     575                "Hold SHIFT or use mouse to select text.\n"
     576                "CTRL+Left/Right to word jump.\n"
     577                "CTRL+A or double-click to select all.\n"
     578                "CTRL+X,CTRL+C,CTRL+V clipboard.\n"
     579                "CTRL+Z,CTRL+Y undo/redo.\n"
     580                "ESCAPE to revert.\n\n"
     581                "PROGRAMMER:\n"
     582                "You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputText() "
     583                "to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example (this is not demonstrated "
     584                "in imgui_demo.cpp).");
     585
     586            static char str1[128] = "";
     587            ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1));
     588
    338589            static int i0 = 123;
    339             ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0));
    340             ImGui::SameLine(); ShowHelpMarker("Hold SHIFT or use mouse to select text.\n" "CTRL+Left/Right to word jump.\n" "CTRL+A or double-click to select all.\n" "CTRL+X,CTRL+C,CTRL+V clipboard.\n" "CTRL+Z,CTRL+Y undo/redo.\n" "ESCAPE to revert.\n");
    341 
    342590            ImGui::InputInt("input int", &i0);
    343             ImGui::SameLine(); ShowHelpMarker("You can apply arithmetic operators +,*,/ on numerical values.\n  e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\nUse +- to subtract.\n");
     591            ImGui::SameLine(); HelpMarker(
     592                "You can apply arithmetic operators +,*,/ on numerical values.\n"
     593                "  e.g. [ 100 ], input \'*2\', result becomes [ 200 ]\n"
     594                "Use +- to subtract.");
    344595
    345596            static float f0 = 0.001f;
    346             ImGui::InputFloat("input float", &f0, 0.01f, 1.0f);
    347 
    348             static double d0 = 999999.000001;
    349             ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.6f");
     597            ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f");
     598
     599            static double d0 = 999999.00000001;
     600            ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f");
    350601
    351602            static float f1 = 1.e10f;
    352603            ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e");
    353             ImGui::SameLine(); ShowHelpMarker("You can input value using the scientific notation,\n  e.g. \"1e+8\" becomes \"100000000\".\n");
     604            ImGui::SameLine(); HelpMarker(
     605                "You can input value using the scientific notation,\n"
     606                "  e.g. \"1e+8\" becomes \"100000000\".");
    354607
    355608            static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
    356609            ImGui::InputFloat3("input float3", vec4a);
    357          }
    358 
    359          {
     610        }
     611
     612        {
    360613            static int i1 = 50, i2 = 42;
    361614            ImGui::DragInt("drag int", &i1, 1);
    362             ImGui::SameLine(); ShowHelpMarker("Click and drag to edit value.\nHold SHIFT/ALT for faster/slower edit.\nDouble-click or CTRL+click to input value.");
    363 
    364             ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%.0f%%");
     615            ImGui::SameLine(); HelpMarker(
     616                "Click and drag to edit value.\n"
     617                "Hold SHIFT/ALT for faster/slower edit.\n"
     618                "Double-click or CTRL+click to input value.");
     619
     620            ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
    365621
    366622            static float f1 = 1.00f, f2 = 0.0067f;
    367623            ImGui::DragFloat("drag float", &f1, 0.005f);
    368624            ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
    369          }
    370 
    371          {
     625        }
     626
     627        {
    372628            static int i1 = 0;
    373629            ImGui::SliderInt("slider int", &i1, -1, 3);
    374             ImGui::SameLine(); ShowHelpMarker("CTRL+click to input value.");
     630            ImGui::SameLine(); HelpMarker("CTRL+click to input value.");
    375631
    376632            static float f1 = 0.123f, f2 = 0.0f;
    377633            ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
    378             ImGui::SliderFloat("slider log float", &f2, -10.0f, 10.0f, "%.4f", 3.0f);
     634            ImGui::SliderFloat("slider float (log)", &f2, -10.0f, 10.0f, "%.4f", ImGuiSliderFlags_Logarithmic);
     635
    379636            static float angle = 0.0f;
    380637            ImGui::SliderAngle("slider angle", &angle);
    381          }
    382 
    383          {
    384             static float col1[3] = { 1.0f,0.0f,0.2f };
    385             static float col2[4] = { 0.4f,0.7f,0.0f,0.5f };
     638
     639            // Using the format string to display a name instead of an integer.
     640            // Here we completely omit '%d' from the format string, so it'll only display a name.
     641            // This technique can also be used with DragInt().
     642            enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
     643            static int elem = Element_Fire;
     644            const char* elems_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
     645            const char* elem_name = (elem >= 0 && elem < Element_COUNT) ? elems_names[elem] : "Unknown";
     646            ImGui::SliderInt("slider enum", &elem, 0, Element_COUNT - 1, elem_name);
     647            ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
     648        }
     649
     650        {
     651            static float col1[3] = { 1.0f, 0.0f, 0.2f };
     652            static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
    386653            ImGui::ColorEdit3("color 1", col1);
    387             ImGui::SameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nRight-click on the colored square to show options.\nCTRL+click on individual component to input value.\n");
     654            ImGui::SameLine(); HelpMarker(
     655                "Click on the colored square to open a color picker.\n"
     656                "Click and hold to use drag and drop.\n"
     657                "Right-click on the colored square to show options.\n"
     658                "CTRL+click on individual component to input value.\n");
    388659
    389660            ImGui::ColorEdit4("color 2", col2);
    390          }
    391 
    392          {
     661        }
     662
     663        {
    393664            // List box
    394             const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
    395             static int listbox_item_current = 1;
    396             ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
     665            const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" };
     666            static int item_current = 1;
     667            ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4);
    397668
    398669            //static int listbox_item_current2 = 2;
    399             //ImGui::PushItemWidth(-1);
     670            //ImGui::SetNextItemWidth(-1);
    400671            //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4);
    401             //ImGui::PopItemWidth();
    402          }
    403 
    404          ImGui::TreePop();
    405       }
    406 
    407       // Testing ImGuiOnceUponAFrame helper.
    408       //static ImGuiOnceUponAFrame once;
    409       //for (int i = 0; i < 5; i++)
    410       //    if (once)
    411       //        ImGui::Text("This will be displayed only once.");
    412 
    413       if (ImGui::TreeNode("Trees"))
    414       {
    415          if (ImGui::TreeNode("Basic trees"))
    416          {
     672        }
     673
     674        ImGui::TreePop();
     675    }
     676
     677    // Testing ImGuiOnceUponAFrame helper.
     678    //static ImGuiOnceUponAFrame once;
     679    //for (int i = 0; i < 5; i++)
     680    //    if (once)
     681    //        ImGui::Text("This will be displayed only once.");
     682
     683    if (ImGui::TreeNode("Trees"))
     684    {
     685        if (ImGui::TreeNode("Basic trees"))
     686        {
    417687            for (int i = 0; i < 5; i++)
    418                if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
    419                {
    420                   ImGui::Text("blah blah");
    421                   ImGui::SameLine();
    422                   if (ImGui::SmallButton("button")) {};
    423                   ImGui::TreePop();
    424                }
     688            {
     689                // Use SetNextItemOpen() so set the default state of a node to be open. We could
     690                // also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
     691                if (i == 0)
     692                    ImGui::SetNextItemOpen(true, ImGuiCond_Once);
     693
     694                if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
     695                {
     696                    ImGui::Text("blah blah");
     697                    ImGui::SameLine();
     698                    if (ImGui::SmallButton("button")) {}
     699                    ImGui::TreePop();
     700                }
     701            }
    425702            ImGui::TreePop();
    426          }
    427 
    428          if (ImGui::TreeNode("Advanced, with Selectable nodes"))
    429          {
    430             ShowHelpMarker("This is a more standard looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open.");
     703        }
     704
     705        if (ImGui::TreeNode("Advanced, with Selectable nodes"))
     706        {
     707            HelpMarker(
     708                "This is a more typical looking tree with selectable nodes.\n"
     709                "Click to select, CTRL+Click to toggle, click on arrows or double-click to open.");
     710            static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
    431711            static bool align_label_with_current_x_position = false;
    432             ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position);
     712            static bool test_drag_and_drop = false;
     713            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow",       (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
     714            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
     715            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth",    (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanAvailWidth); ImGui::SameLine(); HelpMarker("Extend hit area to all available width instead of allowing more items to be laid out after the node.");
     716            ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth",     (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
     717            ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
     718            ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
    433719            ImGui::Text("Hello!");
    434720            if (align_label_with_current_x_position)
    435                ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
    436 
    437             static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit.
    438             int node_clicked = -1;                // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc.
    439             ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize() * 3); // Increase spacing to differentiate leaves from expanded contents.
     721                ImGui::Unindent(ImGui::GetTreeNodeToLabelSpacing());
     722
     723            // 'selection_mask' is dumb representation of what may be user-side selection state.
     724            //  You may retain selection state inside or outside your objects in whatever format you see fit.
     725            // 'node_clicked' is temporary storage of what node we have clicked to process selection at the end
     726            /// of the loop. May be a pointer to your own node type, etc.
     727            static int selection_mask = (1 << 2);
     728            int node_clicked = -1;
    440729            for (int i = 0; i < 6; i++)
    441730            {
    442                // Disable the default open on single-click behavior and pass in Selected flag according to our selection state.
    443                ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ((selection_mask & (1 << i)) ? ImGuiTreeNodeFlags_Selected : 0);
    444                if (i < 3)
    445                {
    446                   // Node
    447                   bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
    448                   if (ImGui::IsItemClicked())
    449                      node_clicked = i;
    450                   if (node_open)
    451                   {
    452                      ImGui::Text("Blah blah\nBlah Blah");
    453                      ImGui::TreePop();
    454                   }
    455                }
    456                else
    457                {
    458                   // Leaf: The only reason we have a TreeNode at all is to allow selection of the leaf. Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text().
    459                   node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
    460                   ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
    461                   if (ImGui::IsItemClicked())
    462                      node_clicked = i;
    463                }
     731                // Disable the default "open on single-click behavior" + set Selected flag according to our selection.
     732                ImGuiTreeNodeFlags node_flags = base_flags;
     733                const bool is_selected = (selection_mask & (1 << i)) != 0;
     734                if (is_selected)
     735                    node_flags |= ImGuiTreeNodeFlags_Selected;
     736                if (i < 3)
     737                {
     738                    // Items 0..2 are Tree Node
     739                    bool node_open = ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Node %d", i);
     740                    if (ImGui::IsItemClicked())
     741                        node_clicked = i;
     742                    if (test_drag_and_drop && ImGui::BeginDragDropSource())
     743                    {
     744                        ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
     745                        ImGui::Text("This is a drag and drop source");
     746                        ImGui::EndDragDropSource();
     747                    }
     748                    if (node_open)
     749                    {
     750                        ImGui::BulletText("Blah blah\nBlah Blah");
     751                        ImGui::TreePop();
     752                    }
     753                }
     754                else
     755                {
     756                    // Items 3..5 are Tree Leaves
     757                    // The only reason we use TreeNode at all is to allow selection of the leaf. Otherwise we can
     758                    // use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
     759                    node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
     760                    ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
     761                    if (ImGui::IsItemClicked())
     762                        node_clicked = i;
     763                    if (test_drag_and_drop && ImGui::BeginDragDropSource())
     764                    {
     765                        ImGui::SetDragDropPayload("_TREENODE", NULL, 0);
     766                        ImGui::Text("This is a drag and drop source");
     767                        ImGui::EndDragDropSource();
     768                    }
     769                }
    464770            }
    465771            if (node_clicked != -1)
    466772            {
    467                // Update selection state. Process outside of tree loop to avoid visual inconsistencies during the clicking-frame.
    468                if (ImGui::GetIO().KeyCtrl)
    469                   selection_mask ^= (1 << node_clicked);          // CTRL+click to toggle
    470                else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection
    471                   selection_mask = (1 << node_clicked);           // Click to single-select
    472             }
    473             ImGui::PopStyleVar();
     773                // Update selection state
     774                // (process outside of tree loop to avoid visual inconsistencies during the clicking frame)
     775                if (ImGui::GetIO().KeyCtrl)
     776                    selection_mask ^= (1 << node_clicked);          // CTRL+click to toggle
     777                else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, may want to preserve selection when clicking on item that is part of the selection
     778                    selection_mask = (1 << node_clicked);           // Click to single-select
     779            }
    474780            if (align_label_with_current_x_position)
    475                ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
     781                ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
    476782            ImGui::TreePop();
    477          }
    478          ImGui::TreePop();
    479       }
    480 
    481       if (ImGui::TreeNode("Collapsing Headers"))
    482       {
    483          static bool closable_group = true;
    484          ImGui::Checkbox("Enable extra group", &closable_group);
    485          if (ImGui::CollapsingHeader("Header"))
    486          {
    487             ImGui::Text("IsItemHovered: %d", IsItemHovered());
     783        }
     784        ImGui::TreePop();
     785    }
     786
     787    if (ImGui::TreeNode("Collapsing Headers"))
     788    {
     789        static bool closable_group = true;
     790        ImGui::Checkbox("Show 2nd header", &closable_group);
     791        if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
     792        {
     793            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
    488794            for (int i = 0; i < 5; i++)
    489                ImGui::Text("Some content %d", i);
    490          }
    491          if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
    492          {
    493             ImGui::Text("IsItemHovered: %d", IsItemHovered());
     795                ImGui::Text("Some content %d", i);
     796        }
     797        if (ImGui::CollapsingHeader("Header with a close button", &closable_group))
     798        {
     799            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
    494800            for (int i = 0; i < 5; i++)
    495                ImGui::Text("More content %d", i);
    496          }
    497          ImGui::TreePop();
    498       }
    499 
    500       if (ImGui::TreeNode("Bullets"))
    501       {
    502          ImGui::BulletText("Bullet point 1");
    503          ImGui::BulletText("Bullet point 2\nOn multiple lines");
    504          ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
    505          ImGui::Bullet(); ImGui::SmallButton("Button");
    506          ImGui::TreePop();
    507       }
    508 
    509       if (ImGui::TreeNode("Text"))
    510       {
    511          if (ImGui::TreeNode("Colored Text"))
    512          {
     801                ImGui::Text("More content %d", i);
     802        }
     803        /*
     804        if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
     805            ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
     806        */
     807        ImGui::TreePop();
     808    }
     809
     810    if (ImGui::TreeNode("Bullets"))
     811    {
     812        ImGui::BulletText("Bullet point 1");
     813        ImGui::BulletText("Bullet point 2\nOn multiple lines");
     814        if (ImGui::TreeNode("Tree node"))
     815        {
     816            ImGui::BulletText("Another bullet point");
     817            ImGui::TreePop();
     818        }
     819        ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
     820        ImGui::Bullet(); ImGui::SmallButton("Button");
     821        ImGui::TreePop();
     822    }
     823
     824    if (ImGui::TreeNode("Text"))
     825    {
     826        if (ImGui::TreeNode("Colored Text"))
     827        {
    513828            // Using shortcut. You can use PushStyleColor()/PopStyleColor() for more flexibility.
    514829            ImGui::TextColored(ImVec4(1.0f, 0.0f, 1.0f, 1.0f), "Pink");
    515830            ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Yellow");
    516831            ImGui::TextDisabled("Disabled");
    517             ImGui::SameLine(); ShowHelpMarker("The TextDisabled color is stored in ImGuiStyle.");
     832            ImGui::SameLine(); HelpMarker("The TextDisabled color is stored in ImGuiStyle.");
    518833            ImGui::TreePop();
    519          }
    520 
    521          if (ImGui::TreeNode("Word Wrapping"))
    522          {
     834        }
     835
     836        if (ImGui::TreeNode("Word Wrapping"))
     837        {
    523838            // Using shortcut. You can use PushTextWrapPos()/PopTextWrapPos() for more flexibility.
    524             ImGui::TextWrapped("This text should automatically wrap on the edge of the window. The current implementation for text wrapping follows simple rules suitable for English and possibly other languages.");
     839            ImGui::TextWrapped(
     840                "This text should automatically wrap on the edge of the window. The current implementation "
     841                "for text wrapping follows simple rules suitable for English and possibly other languages.");
    525842            ImGui::Spacing();
    526843
     
    528845            ImGui::SliderFloat("Wrap width", &wrap_width, -20, 600, "%.0f");
    529846
    530             ImGui::Text("Test paragraph 1:");
    531             ImVec2 pos = ImGui::GetCursorScreenPos();
    532             ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255, 0, 255, 255));
    533             ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
    534             ImGui::Text("The lazy dog is a good dog. This paragraph is made to fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width);
    535             ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
    536             ImGui::PopTextWrapPos();
    537 
    538             ImGui::Text("Test paragraph 2:");
    539             pos = ImGui::GetCursorScreenPos();
    540             ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x + wrap_width, pos.y), ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight()), IM_COL32(255, 0, 255, 255));
    541             ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
    542             ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee   ffffffff. gggggggg!hhhhhhhh");
    543             ImGui::GetWindowDrawList()->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
    544             ImGui::PopTextWrapPos();
     847            ImDrawList* draw_list = ImGui::GetWindowDrawList();
     848            for (int n = 0; n < 2; n++)
     849            {
     850                ImGui::Text("Test paragraph %d:", n);
     851                ImVec2 pos = ImGui::GetCursorScreenPos();
     852                ImVec2 marker_min = ImVec2(pos.x + wrap_width, pos.y);
     853                ImVec2 marker_max = ImVec2(pos.x + wrap_width + 10, pos.y + ImGui::GetTextLineHeight());
     854                ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + wrap_width);
     855                if (n == 0)
     856                    ImGui::Text("The lazy dog is a good dog. This paragraph should fit within %.0f pixels. Testing a 1 character word. The quick brown fox jumps over the lazy dog.", wrap_width);
     857                else
     858                    ImGui::Text("aaaaaaaa bbbbbbbb, c cccccccc,dddddddd. d eeeeeeee   ffffffff. gggggggg!hhhhhhhh");
     859
     860                // Draw actual text bounding box, following by marker of our expected limit (should not overlap!)
     861                draw_list->AddRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), IM_COL32(255, 255, 0, 255));
     862                draw_list->AddRectFilled(marker_min, marker_max, IM_COL32(255, 0, 255, 255));
     863                ImGui::PopTextWrapPos();
     864            }
    545865
    546866            ImGui::TreePop();
    547          }
    548 
    549          if (ImGui::TreeNode("UTF-8 Text"))
    550          {
     867        }
     868
     869        if (ImGui::TreeNode("UTF-8 Text"))
     870        {
    551871            // UTF-8 test with Japanese characters
    552             // (needs a suitable font, try Arial Unicode or M+ fonts http://mplus-fonts.sourceforge.jp/mplus-outline-fonts/index-en.html)
     872            // (Needs a suitable font? Try "Google Noto" or "Arial Unicode". See docs/FONTS.md for details.)
    553873            // - From C++11 you can use the u8"my text" syntax to encode literal strings as UTF-8
    554             // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. Visual Studio save your file as 'UTF-8 without signature')
    555             // - HOWEVER, FOR THIS DEMO FILE, BECAUSE WE WANT TO SUPPORT COMPILER, WE ARE *NOT* INCLUDING RAW UTF-8 CHARACTERS IN THIS SOURCE FILE.
    556             //   Instead we are encoding a few string with hexadecimal constants. Don't do this in your application!
    557             // Note that characters values are preserved even by InputText() if the font cannot be displayed, so you can safely copy & paste garbled characters into another application.
    558             ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->LoadFromFileTTF() manually to load extra character ranges.");
    559             ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)");
     874            // - For earlier compiler, you may be able to encode your sources as UTF-8 (e.g. in Visual Studio, you
     875            //   can save your source files as 'UTF-8 without signature').
     876            // - FOR THIS DEMO FILE ONLY, BECAUSE WE WANT TO SUPPORT OLD COMPILERS, WE ARE *NOT* INCLUDING RAW UTF-8
     877            //   CHARACTERS IN THIS SOURCE FILE. Instead we are encoding a few strings with hexadecimal constants.
     878            //   Don't do this in your application! Please use u8"text in any language" in your application!
     879            // Note that characters values are preserved even by InputText() if the font cannot be displayed,
     880            // so you can safely copy & paste garbled characters into another application.
     881            ImGui::TextWrapped(
     882                "CJK text will only appears if the font was loaded with the appropriate CJK character ranges. "
     883                "Call io.Font->AddFontFromFileTTF() manually to load extra character ranges. "
     884                "Read docs/FONTS.md for details.");
     885            ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); // Normally we would use u8"blah blah" with the proper characters directly in the string.
    560886            ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)");
    561             static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; // "nihongo"
     887            static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
     888            //static char buf[32] = u8"NIHONGO"; // <- this is how you would write it with C++11, using real kanjis
    562889            ImGui::InputText("UTF-8 input", buf, IM_ARRAYSIZE(buf));
    563890            ImGui::TreePop();
    564          }
    565          ImGui::TreePop();
    566       }
    567 
    568       if (ImGui::TreeNode("Images"))
    569       {
    570          ImGuiIO& io = ImGui::GetIO();
    571          ImGui::TextWrapped("Below we are displaying the font texture (which is the only texture we have access to in this demo). Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. Hover the texture for a zoomed view!");
    572 
    573          // Here we are grabbing the font texture because that's the only one we have access to inside the demo code.
    574          // Remember that ImTextureID is just storage for whatever you want it to be, it is essentially a value that will be passed to the render function inside the ImDrawCmd structure.
    575          // If you use one of the default imgui_impl_XXXX.cpp renderer, they all have comments at the top of their file to specify what they expect to be stored in ImTextureID.
    576          // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_glfw_gl3.cpp renderer expect a GLuint OpenGL texture identifier etc.)
    577          // If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc.
    578          // Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this.
    579          // Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
    580          ImTextureID my_tex_id = io.Fonts->TexID;
    581          float my_tex_w = (float)io.Fonts->TexWidth;
    582          float my_tex_h = (float)io.Fonts->TexHeight;
    583 
    584          ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
    585          ImVec2 pos = ImGui::GetCursorScreenPos();
    586          ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128));
    587          if (ImGui::IsItemHovered())
    588          {
    589             ImGui::BeginTooltip();
    590             float region_sz = 32.0f;
    591             float region_x = io.MousePos.x - pos.x - region_sz * 0.5f; if (region_x < 0.0f) region_x = 0.0f; else if (region_x > my_tex_w - region_sz) region_x = my_tex_w - region_sz;
    592             float region_y = io.MousePos.y - pos.y - region_sz * 0.5f; if (region_y < 0.0f) region_y = 0.0f; else if (region_y > my_tex_h - region_sz) region_y = my_tex_h - region_sz;
    593             float zoom = 4.0f;
    594             ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
    595             ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
    596             ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
    597             ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
    598             ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128));
    599             ImGui::EndTooltip();
    600          }
    601          ImGui::TextWrapped("And now some textured buttons..");
    602          static int pressed_count = 0;
    603          for (int i = 0; i < 8; i++)
    604          {
     891        }
     892        ImGui::TreePop();
     893    }
     894
     895    if (ImGui::TreeNode("Images"))
     896    {
     897        ImGuiIO& io = ImGui::GetIO();
     898        ImGui::TextWrapped(
     899            "Below we are displaying the font texture (which is the only texture we have access to in this demo). "
     900            "Use the 'ImTextureID' type as storage to pass pointers or identifier to your own texture data. "
     901            "Hover the texture for a zoomed view!");
     902
     903        // Below we are displaying the font texture because it is the only texture we have access to inside the demo!
     904        // Remember that ImTextureID is just storage for whatever you want it to be. It is essentially a value that
     905        // will be passed to the rendering back-end via the ImDrawCmd structure.
     906        // If you use one of the default imgui_impl_XXXX.cpp rendering back-end, they all have comments at the top
     907        // of their respective source file to specify what they expect to be stored in ImTextureID, for example:
     908        // - The imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer
     909        // - The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier, etc.
     910        // More:
     911        // - If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers
     912        //   to ImGui::Image(), and gather width/height through your own functions, etc.
     913        // - You can use ShowMetricsWindow() to inspect the draw data that are being passed to your renderer,
     914        //   it will help you debug issues if you are confused about it.
     915        // - Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
     916        // - Read https://github.com/ocornut/imgui/blob/master/docs/FAQ.md
     917        // - Read https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
     918        ImTextureID my_tex_id = io.Fonts->TexID;
     919        float my_tex_w = (float)io.Fonts->TexWidth;
     920        float my_tex_h = (float)io.Fonts->TexHeight;
     921        {
     922            ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
     923            ImVec2 pos = ImGui::GetCursorScreenPos();
     924            ImVec2 uv_min = ImVec2(0.0f, 0.0f);                 // Top-left
     925            ImVec2 uv_max = ImVec2(1.0f, 1.0f);                 // Lower-right
     926            ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);   // No tint
     927            ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white
     928            ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
     929            if (ImGui::IsItemHovered())
     930            {
     931                ImGui::BeginTooltip();
     932                float region_sz = 32.0f;
     933                float region_x = io.MousePos.x - pos.x - region_sz * 0.5f;
     934                float region_y = io.MousePos.y - pos.y - region_sz * 0.5f;
     935                float zoom = 4.0f;
     936                if (region_x < 0.0f) { region_x = 0.0f; }
     937                else if (region_x > my_tex_w - region_sz) { region_x = my_tex_w - region_sz; }
     938                if (region_y < 0.0f) { region_y = 0.0f; }
     939                else if (region_y > my_tex_h - region_sz) { region_y = my_tex_h - region_sz; }
     940                ImGui::Text("Min: (%.2f, %.2f)", region_x, region_y);
     941                ImGui::Text("Max: (%.2f, %.2f)", region_x + region_sz, region_y + region_sz);
     942                ImVec2 uv0 = ImVec2((region_x) / my_tex_w, (region_y) / my_tex_h);
     943                ImVec2 uv1 = ImVec2((region_x + region_sz) / my_tex_w, (region_y + region_sz) / my_tex_h);
     944                ImGui::Image(my_tex_id, ImVec2(region_sz * zoom, region_sz * zoom), uv0, uv1, tint_col, border_col);
     945                ImGui::EndTooltip();
     946            }
     947        }
     948        ImGui::TextWrapped("And now some textured buttons..");
     949        static int pressed_count = 0;
     950        for (int i = 0; i < 8; i++)
     951        {
    605952            ImGui::PushID(i);
    606             int frame_padding = -1 + i;     // -1 = uses default padding
    607             if (ImGui::ImageButton(my_tex_id, ImVec2(32, 32), ImVec2(0, 0), ImVec2(32.0f / my_tex_w, 32 / my_tex_h), frame_padding, ImColor(0, 0, 0, 255)))
    608                pressed_count += 1;
     953            int frame_padding = -1 + i;                             // -1 == uses default padding (style.FramePadding)
     954            ImVec2 size = ImVec2(32.0f, 32.0f);                     // Size of the image we want to make visible
     955            ImVec2 uv0 = ImVec2(0.0f, 0.0f);                        // UV coordinates for lower-left
     956            ImVec2 uv1 = ImVec2(32.0f / my_tex_w, 32.0f / my_tex_h);// UV coordinates for (32,32) in our texture
     957            ImVec4 bg_col = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);         // Black background
     958            ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);       // No tint
     959            if (ImGui::ImageButton(my_tex_id, size, uv0, uv1, frame_padding, bg_col, tint_col))
     960                pressed_count += 1;
    609961            ImGui::PopID();
    610962            ImGui::SameLine();
    611          }
    612          ImGui::NewLine();
    613          ImGui::Text("Pressed %d times.", pressed_count);
    614          ImGui::TreePop();
    615       }
    616 
    617       if (ImGui::TreeNode("Combo"))
    618       {
    619          // Expose flags as checkbox for the demo
    620          static ImGuiComboFlags flags = 0;
    621          ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft);
    622          if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton))
     963        }
     964        ImGui::NewLine();
     965        ImGui::Text("Pressed %d times.", pressed_count);
     966        ImGui::TreePop();
     967    }
     968
     969    if (ImGui::TreeNode("Combo"))
     970    {
     971        // Expose flags as checkbox for the demo
     972        static ImGuiComboFlags flags = 0;
     973        ImGui::CheckboxFlags("ImGuiComboFlags_PopupAlignLeft", (unsigned int*)&flags, ImGuiComboFlags_PopupAlignLeft);
     974        ImGui::SameLine(); HelpMarker("Only makes a difference if the popup is larger than the combo");
     975        if (ImGui::CheckboxFlags("ImGuiComboFlags_NoArrowButton", (unsigned int*)&flags, ImGuiComboFlags_NoArrowButton))
    623976            flags &= ~ImGuiComboFlags_NoPreview;     // Clear the other flag, as we cannot combine both
    624          if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview))
     977        if (ImGui::CheckboxFlags("ImGuiComboFlags_NoPreview", (unsigned int*)&flags, ImGuiComboFlags_NoPreview))
    625978            flags &= ~ImGuiComboFlags_NoArrowButton; // Clear the other flag, as we cannot combine both
    626979
    627                                                      // General BeginCombo() API, you have full control over your selection data and display type.
    628                                                      // (your selection data could be an index, a pointer to the object, an id for the object, a flag stored in the object itself, etc.)
    629          const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
    630          static const char* item_current = items[0];            // Here our selection is a single pointer stored outside the object.
    631          if (ImGui::BeginCombo("combo 1", item_current, flags)) // The second parameter is the label previewed before opening the combo.
    632          {
     980        // Using the generic BeginCombo() API, you have full control over how to display the combo contents.
     981        // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
     982        // stored in the object itself, etc.)
     983        const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
     984        static int item_current_idx = 0;                    // Here our selection data is an index.
     985        const char* combo_label = items[item_current_idx];  // Label to preview before opening the combo (technically it could be anything)
     986        if (ImGui::BeginCombo("combo 1", combo_label, flags))
     987        {
    633988            for (int n = 0; n < IM_ARRAYSIZE(items); n++)
    634989            {
    635                bool is_selected = (item_current == items[n]);
    636                if (ImGui::Selectable(items[n], is_selected))
    637                   item_current = items[n];
    638                if (is_selected)
    639                   ImGui::SetItemDefaultFocus();   // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
     990                const bool is_selected = (item_current_idx == n);
     991                if (ImGui::Selectable(items[n], is_selected))
     992                    item_current_idx = n;
     993
     994                // Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
     995                if (is_selected)
     996                    ImGui::SetItemDefaultFocus();
    640997            }
    641998            ImGui::EndCombo();
    642          }
    643 
    644          // Simplified one-liner Combo() API, using values packed in a single constant string
    645          static int item_current_2 = 0;
    646          ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
    647 
    648          // Simplified one-liner Combo() using an array of const char*
    649          static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
    650          ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
    651 
    652          // Simplified one-liner Combo() using an accessor function
    653          struct FuncHolder { static bool ItemGetter(void* data, int idx, const char** out_str) { *out_str = ((const char**)data)[idx]; return true; } };
    654          static int item_current_4 = 0;
    655          ImGui::Combo("combo 4 (function)", &item_current_4, &FuncHolder::ItemGetter, items, IM_ARRAYSIZE(items));
    656 
    657          ImGui::TreePop();
    658       }
    659 
    660       if (ImGui::TreeNode("Selectables"))
    661       {
    662          // Selectable() has 2 overloads:
    663          // - The one taking "bool selected" as a read-only selection information. When Selectable() has been clicked is returns true and you can alter selection state accordingly.
    664          // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
    665          // The earlier is more flexible, as in real application your selection may be stored in a different manner (in flags within objects, as an external list, etc).
    666          if (ImGui::TreeNode("Basic"))
    667          {
     999        }
     1000
     1001        // Simplified one-liner Combo() API, using values packed in a single constant string
     1002        static int item_current_2 = 0;
     1003        ImGui::Combo("combo 2 (one-liner)", &item_current_2, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
     1004
     1005        // Simplified one-liner Combo() using an array of const char*
     1006        static int item_current_3 = -1; // If the selection isn't within 0..count, Combo won't display a preview
     1007        ImGui::Combo("combo 3 (array)", &item_current_3, items, IM_ARRAYSIZE(items));
     1008
     1009        // Simplified one-liner Combo() using an accessor function
     1010        struct Funcs { static bool ItemGetter(void* data, int n, const char** out_str) { *out_str = ((const char**)data)[n]; return true; } };
     1011        static int item_current_4 = 0;
     1012        ImGui::Combo("combo 4 (function)", &item_current_4, &Funcs::ItemGetter, items, IM_ARRAYSIZE(items));
     1013
     1014        ImGui::TreePop();
     1015    }
     1016
     1017    if (ImGui::TreeNode("Selectables"))
     1018    {
     1019        // Selectable() has 2 overloads:
     1020        // - The one taking "bool selected" as a read-only selection information.
     1021        //   When Selectable() has been clicked it returns true and you can alter selection state accordingly.
     1022        // - The one taking "bool* p_selected" as a read-write selection information (convenient in some cases)
     1023        // The earlier is more flexible, as in real application your selection may be stored in many different ways
     1024        // and not necessarily inside a bool value (e.g. in flags within objects, as an external list, etc).
     1025        if (ImGui::TreeNode("Basic"))
     1026        {
    6681027            static bool selection[5] = { false, true, false, false, false };
    6691028            ImGui::Selectable("1. I am selectable", &selection[0]);
     
    6721031            ImGui::Selectable("4. I am selectable", &selection[3]);
    6731032            if (ImGui::Selectable("5. I am double clickable", selection[4], ImGuiSelectableFlags_AllowDoubleClick))
    674                if (ImGui::IsMouseDoubleClicked(0))
    675                   selection[4] = !selection[4];
     1033                if (ImGui::IsMouseDoubleClicked(0))
     1034                    selection[4] = !selection[4];
    6761035            ImGui::TreePop();
    677          }
    678          if (ImGui::TreeNode("Selection State: Single Selection"))
    679          {
     1036        }
     1037        if (ImGui::TreeNode("Selection State: Single Selection"))
     1038        {
    6801039            static int selected = -1;
    6811040            for (int n = 0; n < 5; n++)
    6821041            {
    683                char buf[32];
    684                sprintf(buf, "Object %d", n);
    685                if (ImGui::Selectable(buf, selected == n))
    686                   selected = n;
     1042                char buf[32];
     1043                sprintf(buf, "Object %d", n);
     1044                if (ImGui::Selectable(buf, selected == n))
     1045                    selected = n;
    6871046            }
    6881047            ImGui::TreePop();
    689          }
    690          if (ImGui::TreeNode("Selection State: Multiple Selection"))
    691          {
    692             ShowHelpMarker("Hold CTRL and click to select multiple items.");
     1048        }
     1049        if (ImGui::TreeNode("Selection State: Multiple Selection"))
     1050        {
     1051            HelpMarker("Hold CTRL and click to select multiple items.");
    6931052            static bool selection[5] = { false, false, false, false, false };
    6941053            for (int n = 0; n < 5; n++)
    6951054            {
    696                char buf[32];
    697                sprintf(buf, "Object %d", n);
    698                if (ImGui::Selectable(buf, selection[n]))
    699                {
    700                   if (!ImGui::GetIO().KeyCtrl)    // Clear selection when CTRL is not held
    701                      memset(selection, 0, sizeof(selection));
    702                   selection[n] ^= 1;
    703                }
     1055                char buf[32];
     1056                sprintf(buf, "Object %d", n);
     1057                if (ImGui::Selectable(buf, selection[n]))
     1058                {
     1059                    if (!ImGui::GetIO().KeyCtrl)    // Clear selection when CTRL is not held
     1060                        memset(selection, 0, sizeof(selection));
     1061                    selection[n] ^= 1;
     1062                }
    7041063            }
    7051064            ImGui::TreePop();
    706          }
    707          if (ImGui::TreeNode("Rendering more text into the same line"))
    708          {
    709             // Using the Selectable() override that takes "bool* p_selected" parameter and toggle your booleans automatically.
     1065        }
     1066        if (ImGui::TreeNode("Rendering more text into the same line"))
     1067        {
     1068            // Using the Selectable() override that takes "bool* p_selected" parameter,
     1069            // this function toggle your bool value automatically.
    7101070            static bool selected[3] = { false, false, false };
    711             ImGui::Selectable("main.c", &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
     1071            ImGui::Selectable("main.c",    &selected[0]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
    7121072            ImGui::Selectable("Hello.cpp", &selected[1]); ImGui::SameLine(300); ImGui::Text("12,345 bytes");
    713             ImGui::Selectable("Hello.h", &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
     1073            ImGui::Selectable("Hello.h",   &selected[2]); ImGui::SameLine(300); ImGui::Text(" 2,345 bytes");
    7141074            ImGui::TreePop();
    715          }
    716          if (ImGui::TreeNode("In columns"))
    717          {
     1075        }
     1076        if (ImGui::TreeNode("In columns"))
     1077        {
    7181078            ImGui::Columns(3, NULL, false);
    719             static bool selected[16] = { 0 };
     1079            static bool selected[16] = {};
    7201080            for (int i = 0; i < 16; i++)
    7211081            {
    722                char label[32]; sprintf(label, "Item %d", i);
    723                if (ImGui::Selectable(label, &selected[i])) {}
    724                ImGui::NextColumn();
     1082                char label[32]; sprintf(label, "Item %d", i);
     1083                if (ImGui::Selectable(label, &selected[i])) {}
     1084                ImGui::NextColumn();
    7251085            }
    7261086            ImGui::Columns(1);
    7271087            ImGui::TreePop();
    728          }
    729          if (ImGui::TreeNode("Grid"))
    730          {
    731             static bool selected[16] = { true, false, false, false, false, true, false, false, false, false, true, false, false, false, false, true };
    732             for (int i = 0; i < 16; i++)
    733             {
    734                ImGui::PushID(i);
    735                if (ImGui::Selectable("Sailor", &selected[i], 0, ImVec2(50, 50)))
    736                {
    737                   int x = i % 4, y = i / 4;
    738                   if (x > 0) selected[i - 1] ^= 1;
    739                   if (x < 3) selected[i + 1] ^= 1;
    740                   if (y > 0) selected[i - 4] ^= 1;
    741                   if (y < 3) selected[i + 4] ^= 1;
    742                }
    743                if ((i % 4) < 3) ImGui::SameLine();
    744                ImGui::PopID();
    745             }
     1088        }
     1089        if (ImGui::TreeNode("Grid"))
     1090        {
     1091            static char selected[4][4] = { { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 } };
     1092
     1093            // Add in a bit of silly fun...
     1094            const float time = (float)ImGui::GetTime();
     1095            const bool winning_state = memchr(selected, 0, sizeof(selected)) == NULL; // If all cells are selected...
     1096            if (winning_state)
     1097                ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f + 0.5f * cosf(time * 2.0f), 0.5f + 0.5f * sinf(time * 3.0f)));
     1098
     1099            for (int y = 0; y < 4; y++)
     1100                for (int x = 0; x < 4; x++)
     1101                {
     1102                    if (x > 0)
     1103                        ImGui::SameLine();
     1104                    ImGui::PushID(y * 4 + x);
     1105                    if (ImGui::Selectable("Sailor", selected[y][x] != 0, 0, ImVec2(50, 50)))
     1106                    {
     1107                        // Toggle clicked cell + toggle neighbors
     1108                        selected[y][x] ^= 1;
     1109                        if (x > 0) { selected[y][x - 1] ^= 1; }
     1110                        if (x < 3) { selected[y][x + 1] ^= 1; }
     1111                        if (y > 0) { selected[y - 1][x] ^= 1; }
     1112                        if (y < 3) { selected[y + 1][x] ^= 1; }
     1113                    }
     1114                    ImGui::PopID();
     1115                }
     1116
     1117            if (winning_state)
     1118                ImGui::PopStyleVar();
    7461119            ImGui::TreePop();
    747          }
    748          ImGui::TreePop();
    749       }
    750 
    751       if (ImGui::TreeNode("Filtered Text Input"))
    752       {
    753          static char buf1[64] = ""; ImGui::InputText("default", buf1, 64);
    754          static char buf2[64] = ""; ImGui::InputText("decimal", buf2, 64, ImGuiInputTextFlags_CharsDecimal);
    755          static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
    756          static char buf4[64] = ""; ImGui::InputText("uppercase", buf4, 64, ImGuiInputTextFlags_CharsUppercase);
    757          static char buf5[64] = ""; ImGui::InputText("no blank", buf5, 64, ImGuiInputTextFlags_CharsNoBlank);
    758          struct TextFilters { static int FilterImGuiLetters(ImGuiTextEditCallbackData* data) { if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar)) return 0; return 1; } };
    759          static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters);
    760 
    761          ImGui::Text("Password input");
    762          static char bufpass[64] = "password123";
    763          ImGui::InputText("password", bufpass, 64, ImGuiInputTextFlags_Password | ImGuiInputTextFlags_CharsNoBlank);
    764          ImGui::SameLine(); ShowHelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
    765          ImGui::InputText("password (clear)", bufpass, 64, ImGuiInputTextFlags_CharsNoBlank);
    766 
    767          ImGui::TreePop();
    768       }
    769 
    770       if (ImGui::TreeNode("Multi-line Text Input"))
    771       {
    772          static bool read_only = false;
    773          static char text[1024 * 16] =
    774             "/*\n"
    775             " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
    776             " the hexadecimal encoding of one offending instruction,\n"
    777             " more formally, the invalid operand with locked CMPXCHG8B\n"
    778             " instruction bug, is a design flaw in the majority of\n"
    779             " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
    780             " processors (all in the P5 microarchitecture).\n"
    781             "*/\n\n"
    782             "label:\n"
    783             "\tlock cmpxchg8b eax\n";
    784 
    785          ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
    786          ImGui::Checkbox("Read-only", &read_only);
    787          ImGui::PopStyleVar();
    788          ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), ImGuiInputTextFlags_AllowTabInput | (read_only ? ImGuiInputTextFlags_ReadOnly : 0));
    789          ImGui::TreePop();
    790       }
    791 
    792       if (ImGui::TreeNode("Plots widgets"))
    793       {
    794          static bool animate = true;
    795          ImGui::Checkbox("Animate", &animate);
    796 
    797          static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
    798          ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
    799 
    800          // Create a dummy array of contiguous float values to plot
    801          // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float and the sizeof() of your structure in the Stride parameter.
    802          static float values[90] = { 0 };
    803          static int values_offset = 0;
    804          static float refresh_time = 0.0f;
    805          if (!animate || refresh_time == 0.0f)
     1120        }
     1121        if (ImGui::TreeNode("Alignment"))
     1122        {
     1123            HelpMarker(
     1124                "By default, Selectables uses style.SelectableTextAlign but it can be overridden on a per-item "
     1125                "basis using PushStyleVar(). You'll probably want to always keep your default situation to "
     1126                "left-align otherwise it becomes difficult to layout multiple items on a same line");
     1127            static bool selected[3 * 3] = { true, false, true, false, true, false, true, false, true };
     1128            for (int y = 0; y < 3; y++)
     1129            {
     1130                for (int x = 0; x < 3; x++)
     1131                {
     1132                    ImVec2 alignment = ImVec2((float)x / 2.0f, (float)y / 2.0f);
     1133                    char name[32];
     1134                    sprintf(name, "(%.1f,%.1f)", alignment.x, alignment.y);
     1135                    if (x > 0) ImGui::SameLine();
     1136                    ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, alignment);
     1137                    ImGui::Selectable(name, &selected[3 * y + x], ImGuiSelectableFlags_None, ImVec2(80, 80));
     1138                    ImGui::PopStyleVar();
     1139                }
     1140            }
     1141            ImGui::TreePop();
     1142        }
     1143        ImGui::TreePop();
     1144    }
     1145
     1146    // To wire InputText() with std::string or any other custom string type,
     1147    // see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
     1148    if (ImGui::TreeNode("Text Input"))
     1149    {
     1150        if (ImGui::TreeNode("Multi-line Text Input"))
     1151        {
     1152            // Note: we are using a fixed-sized buffer for simplicity here. See ImGuiInputTextFlags_CallbackResize
     1153            // and the code in misc/cpp/imgui_stdlib.h for how to setup InputText() for dynamically resizing strings.
     1154            static char text[1024 * 16] =
     1155                "/*\n"
     1156                " The Pentium F00F bug, shorthand for F0 0F C7 C8,\n"
     1157                " the hexadecimal encoding of one offending instruction,\n"
     1158                " more formally, the invalid operand with locked CMPXCHG8B\n"
     1159                " instruction bug, is a design flaw in the majority of\n"
     1160                " Intel Pentium, Pentium MMX, and Pentium OverDrive\n"
     1161                " processors (all in the P5 microarchitecture).\n"
     1162                "*/\n\n"
     1163                "label:\n"
     1164                "\tlock cmpxchg8b eax\n";
     1165
     1166            static ImGuiInputTextFlags flags = ImGuiInputTextFlags_AllowTabInput;
     1167            HelpMarker("You can use the ImGuiInputTextFlags_CallbackResize facility if you need to wire InputTextMultiline() to a dynamic string type. See misc/cpp/imgui_stdlib.h for an example. (This is not demonstrated in imgui_demo.cpp because we don't want to include <string> in here)");
     1168            ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly);
     1169            ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput);
     1170            ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
     1171            ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
     1172            ImGui::TreePop();
     1173        }
     1174
     1175        if (ImGui::TreeNode("Filtered Text Input"))
     1176        {
     1177            struct TextFilters
     1178            {
     1179                // Return 0 (pass) if the character is 'i' or 'm' or 'g' or 'u' or 'i'
     1180                static int FilterImGuiLetters(ImGuiInputTextCallbackData* data)
     1181                {
     1182                    if (data->EventChar < 256 && strchr("imgui", (char)data->EventChar))
     1183                        return 0;
     1184                    return 1;
     1185                }
     1186            };
     1187
     1188            static char buf1[64] = ""; ImGui::InputText("default",     buf1, 64);
     1189            static char buf2[64] = ""; ImGui::InputText("decimal",     buf2, 64, ImGuiInputTextFlags_CharsDecimal);
     1190            static char buf3[64] = ""; ImGui::InputText("hexadecimal", buf3, 64, ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
     1191            static char buf4[64] = ""; ImGui::InputText("uppercase",   buf4, 64, ImGuiInputTextFlags_CharsUppercase);
     1192            static char buf5[64] = ""; ImGui::InputText("no blank",    buf5, 64, ImGuiInputTextFlags_CharsNoBlank);
     1193            static char buf6[64] = ""; ImGui::InputText("\"imgui\" letters", buf6, 64, ImGuiInputTextFlags_CallbackCharFilter, TextFilters::FilterImGuiLetters);
     1194            ImGui::TreePop();
     1195        }
     1196
     1197        if (ImGui::TreeNode("Password Input"))
     1198        {
     1199            static char password[64] = "password123";
     1200            ImGui::InputText("password", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
     1201            ImGui::SameLine(); HelpMarker("Display all characters as '*'.\nDisable clipboard cut and copy.\nDisable logging.\n");
     1202            ImGui::InputTextWithHint("password (w/ hint)", "<password>", password, IM_ARRAYSIZE(password), ImGuiInputTextFlags_Password);
     1203            ImGui::InputText("password (clear)", password, IM_ARRAYSIZE(password));
     1204            ImGui::TreePop();
     1205        }
     1206
     1207        if (ImGui::TreeNode("Completion, History, Edit Callbacks"))
     1208        {
     1209            struct Funcs
     1210            {
     1211                static int MyCallback(ImGuiInputTextCallbackData* data)
     1212                {
     1213                    if (data->EventFlag == ImGuiInputTextFlags_CallbackCompletion)
     1214                    {
     1215                        data->InsertChars(data->CursorPos, "..");
     1216                    }
     1217                    else if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
     1218                    {
     1219                        if (data->EventKey == ImGuiKey_UpArrow)
     1220                        {
     1221                            data->DeleteChars(0, data->BufTextLen);
     1222                            data->InsertChars(0, "Pressed Up!");
     1223                            data->SelectAll();
     1224                        }
     1225                        else if (data->EventKey == ImGuiKey_DownArrow)
     1226                        {
     1227                            data->DeleteChars(0, data->BufTextLen);
     1228                            data->InsertChars(0, "Pressed Down!");
     1229                            data->SelectAll();
     1230                        }
     1231                    }
     1232                    else if (data->EventFlag == ImGuiInputTextFlags_CallbackEdit)
     1233                    {
     1234                        // Toggle casing of first character
     1235                        char c = data->Buf[0];
     1236                        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) data->Buf[0] ^= 32;
     1237                        data->BufDirty = true;
     1238
     1239                        // Increment a counter
     1240                        int* p_int = (int*)data->UserData;
     1241                        *p_int = *p_int + 1;
     1242                    }
     1243                    return 0;
     1244                }
     1245            };
     1246            static char buf1[64];
     1247            ImGui::InputText("Completion", buf1, 64, ImGuiInputTextFlags_CallbackCompletion, Funcs::MyCallback);
     1248            ImGui::SameLine(); HelpMarker("Here we append \"..\" each time Tab is pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.");
     1249
     1250            static char buf2[64];
     1251            ImGui::InputText("History", buf2, 64, ImGuiInputTextFlags_CallbackHistory, Funcs::MyCallback);
     1252            ImGui::SameLine(); HelpMarker("Here we replace and select text each time Up/Down are pressed. See 'Examples>Console' for a more meaningful demonstration of using this callback.");
     1253
     1254            static char buf3[64];
     1255            static int edit_count = 0;
     1256            ImGui::InputText("Edit", buf3, 64, ImGuiInputTextFlags_CallbackEdit, Funcs::MyCallback, (void*)&edit_count);
     1257            ImGui::SameLine(); HelpMarker("Here we toggle the casing of the first character on every edits + count edits.");
     1258            ImGui::SameLine(); ImGui::Text("(%d)", edit_count);
     1259
     1260            ImGui::TreePop();
     1261        }
     1262
     1263        if (ImGui::TreeNode("Resize Callback"))
     1264        {
     1265            // To wire InputText() with std::string or any other custom string type,
     1266            // you can use the ImGuiInputTextFlags_CallbackResize flag + create a custom ImGui::InputText() wrapper
     1267            // using your preferred type. See misc/cpp/imgui_stdlib.h for an implementation of this using std::string.
     1268            HelpMarker(
     1269                "Using ImGuiInputTextFlags_CallbackResize to wire your custom string type to InputText().\n\n"
     1270                "See misc/cpp/imgui_stdlib.h for an implementation of this for std::string.");
     1271            struct Funcs
     1272            {
     1273                static int MyResizeCallback(ImGuiInputTextCallbackData* data)
     1274                {
     1275                    if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
     1276                    {
     1277                        ImVector<char>* my_str = (ImVector<char>*)data->UserData;
     1278                        IM_ASSERT(my_str->begin() == data->Buf);
     1279                        my_str->resize(data->BufSize); // NB: On resizing calls, generally data->BufSize == data->BufTextLen + 1
     1280                        data->Buf = my_str->begin();
     1281                    }
     1282                    return 0;
     1283                }
     1284
     1285                // Note: Because ImGui:: is a namespace you would typically add your own function into the namespace.
     1286                // For example, you code may declare a function 'ImGui::InputText(const char* label, MyString* my_str)'
     1287                static bool MyInputTextMultiline(const char* label, ImVector<char>* my_str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0)
     1288                {
     1289                    IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
     1290                    return ImGui::InputTextMultiline(label, my_str->begin(), (size_t)my_str->size(), size, flags | ImGuiInputTextFlags_CallbackResize, Funcs::MyResizeCallback, (void*)my_str);
     1291                }
     1292            };
     1293
     1294            // For this demo we are using ImVector as a string container.
     1295            // Note that because we need to store a terminating zero character, our size/capacity are 1 more
     1296            // than usually reported by a typical string class.
     1297            static ImVector<char> my_str;
     1298            if (my_str.empty())
     1299                my_str.push_back(0);
     1300            Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
     1301            ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
     1302            ImGui::TreePop();
     1303        }
     1304
     1305        ImGui::TreePop();
     1306    }
     1307
     1308    // Plot/Graph widgets are currently fairly limited.
     1309    // Consider writing your own plotting widget, or using a third-party one
     1310    // (for third-party Plot widgets, see 'Wiki->Useful Widgets' or https://github.com/ocornut/imgui/labels/plot%2Fgraph)
     1311    if (ImGui::TreeNode("Plots Widgets"))
     1312    {
     1313        static bool animate = true;
     1314        ImGui::Checkbox("Animate", &animate);
     1315
     1316        static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
     1317        ImGui::PlotLines("Frame Times", arr, IM_ARRAYSIZE(arr));
     1318
     1319        // Fill an array of contiguous float values to plot
     1320        // Tip: If your float aren't contiguous but part of a structure, you can pass a pointer to your first float
     1321        // and the sizeof() of your structure in the "stride" parameter.
     1322        static float values[90] = {};
     1323        static int values_offset = 0;
     1324        static double refresh_time = 0.0;
     1325        if (!animate || refresh_time == 0.0)
    8061326            refresh_time = ImGui::GetTime();
    807          while (refresh_time < ImGui::GetTime()) // Create dummy data at fixed 60 hz rate for the demo
    808          {
     1327        while (refresh_time < ImGui::GetTime()) // Create data at fixed 60 Hz rate for the demo
     1328        {
    8091329            static float phase = 0.0f;
    8101330            values[values_offset] = cosf(phase);
    8111331            values_offset = (values_offset + 1) % IM_ARRAYSIZE(values);
    812             phase += 0.10f*values_offset;
     1332            phase += 0.10f * values_offset;
    8131333            refresh_time += 1.0f / 60.0f;
    814          }
    815          ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0, 80));
    816          ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80));
    817 
    818          // Use functions to generate output
    819          // FIXME: This is rather awkward because current plot API only pass in indices. We probably want an API passing floats and user provide sample rate/count.
    820          struct Funcs
    821          {
     1334        }
     1335
     1336        // Plots can display overlay texts
     1337        // (in this example, we will display an average value)
     1338        {
     1339            float average = 0.0f;
     1340            for (int n = 0; n < IM_ARRAYSIZE(values); n++)
     1341                average += values[n];
     1342            average /= (float)IM_ARRAYSIZE(values);
     1343            char overlay[32];
     1344            sprintf(overlay, "avg %f", average);
     1345            ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0, 80.0f));
     1346        }
     1347        ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0, 80.0f));
     1348
     1349        // Use functions to generate output
     1350        // FIXME: This is rather awkward because current plot API only pass in indices.
     1351        // We probably want an API passing floats and user provide sample rate/count.
     1352        struct Funcs
     1353        {
    8221354            static float Sin(void*, int i) { return sinf(i * 0.1f); }
    8231355            static float Saw(void*, int i) { return (i & 1) ? 1.0f : -1.0f; }
    824          };
    825          static int func_type = 0, display_count = 70;
    826          ImGui::Separator();
    827          ImGui::PushItemWidth(100); ImGui::Combo("func", &func_type, "Sin\0Saw\0"); ImGui::PopItemWidth();
    828          ImGui::SameLine();
    829          ImGui::SliderInt("Sample count", &display_count, 1, 400);
    830          float(*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
    831          ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
    832          ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
    833          ImGui::Separator();
    834 
    835          // Animate a simple progress bar
    836          static float progress = 0.0f, progress_dir = 1.0f;
    837          if (animate)
    838          {
     1356        };
     1357        static int func_type = 0, display_count = 70;
     1358        ImGui::Separator();
     1359        ImGui::SetNextItemWidth(100);
     1360        ImGui::Combo("func", &func_type, "Sin\0Saw\0");
     1361        ImGui::SameLine();
     1362        ImGui::SliderInt("Sample count", &display_count, 1, 400);
     1363        float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
     1364        ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
     1365        ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
     1366        ImGui::Separator();
     1367
     1368        // Animate a simple progress bar
     1369        static float progress = 0.0f, progress_dir = 1.0f;
     1370        if (animate)
     1371        {
    8391372            progress += progress_dir * 0.4f * ImGui::GetIO().DeltaTime;
    8401373            if (progress >= +1.1f) { progress = +1.1f; progress_dir *= -1.0f; }
    8411374            if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
    842          }
    843 
    844          // Typically we would use ImVec2(-1.0f,0.0f) to use all available width, or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
    845          ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
    846          ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
    847          ImGui::Text("Progress Bar");
    848 
    849          float progress_saturated = (progress < 0.0f) ? 0.0f : (progress > 1.0f) ? 1.0f : progress;
    850          char buf[32];
    851          sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
    852          ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
    853          ImGui::TreePop();
    854       }
    855 
    856       if (ImGui::TreeNode("Color/Picker Widgets"))
    857       {
    858          static ImVec4 color = ImColor(114, 144, 154, 200);
    859 
    860          static bool alpha_preview = true;
    861          static bool alpha_half_preview = false;
    862          static bool options_menu = true;
    863          static bool hdr = false;
    864          ImGui::Checkbox("With Alpha Preview", &alpha_preview);
    865          ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
    866          ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); ShowHelpMarker("Right-click on the individual color widget to show options.");
    867          ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); ShowHelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
    868          int misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
    869 
    870          ImGui::Text("Color widget:");
    871          ImGui::SameLine(); ShowHelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n");
    872          ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
    873 
    874          ImGui::Text("Color widget HSV with Alpha:");
    875          ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_HSV | misc_flags);
    876 
    877          ImGui::Text("Color widget with Float Display:");
    878          ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
    879 
    880          ImGui::Text("Color button with Picker:");
    881          ImGui::SameLine(); ShowHelpMarker("With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\nWith the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only be used for the tooltip and picker popup.");
    882          ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
    883 
    884          ImGui::Text("Color button with Custom Picker Popup:");
    885 
    886          // Generate a dummy palette
    887          static bool saved_palette_inited = false;
    888          static ImVec4 saved_palette[32];
    889          if (!saved_palette_inited)
     1375        }
     1376
     1377        // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
     1378        // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
     1379        ImGui::ProgressBar(progress, ImVec2(0.0f, 0.0f));
     1380        ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
     1381        ImGui::Text("Progress Bar");
     1382
     1383        float progress_saturated = IM_CLAMP(progress, 0.0f, 1.0f);
     1384        char buf[32];
     1385        sprintf(buf, "%d/%d", (int)(progress_saturated * 1753), 1753);
     1386        ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), buf);
     1387        ImGui::TreePop();
     1388    }
     1389
     1390    if (ImGui::TreeNode("Color/Picker Widgets"))
     1391    {
     1392        static ImVec4 color = ImVec4(114.0f / 255.0f, 144.0f / 255.0f, 154.0f / 255.0f, 200.0f / 255.0f);
     1393
     1394        static bool alpha_preview = true;
     1395        static bool alpha_half_preview = false;
     1396        static bool drag_and_drop = true;
     1397        static bool options_menu = true;
     1398        static bool hdr = false;
     1399        ImGui::Checkbox("With Alpha Preview", &alpha_preview);
     1400        ImGui::Checkbox("With Half Alpha Preview", &alpha_half_preview);
     1401        ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
     1402        ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
     1403        ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
     1404        ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
     1405
     1406        ImGui::Text("Color widget:");
     1407        ImGui::SameLine(); HelpMarker(
     1408            "Click on the colored square to open a color picker.\n"
     1409            "CTRL+click on individual component to input value.\n");
     1410        ImGui::ColorEdit3("MyColor##1", (float*)&color, misc_flags);
     1411
     1412        ImGui::Text("Color widget HSV with Alpha:");
     1413        ImGui::ColorEdit4("MyColor##2", (float*)&color, ImGuiColorEditFlags_DisplayHSV | misc_flags);
     1414
     1415        ImGui::Text("Color widget with Float Display:");
     1416        ImGui::ColorEdit4("MyColor##2f", (float*)&color, ImGuiColorEditFlags_Float | misc_flags);
     1417
     1418        ImGui::Text("Color button with Picker:");
     1419        ImGui::SameLine(); HelpMarker(
     1420            "With the ImGuiColorEditFlags_NoInputs flag you can hide all the slider/text inputs.\n"
     1421            "With the ImGuiColorEditFlags_NoLabel flag you can pass a non-empty label which will only "
     1422            "be used for the tooltip and picker popup.");
     1423        ImGui::ColorEdit4("MyColor##3", (float*)&color, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | misc_flags);
     1424
     1425        ImGui::Text("Color button with Custom Picker Popup:");
     1426
     1427        // Generate a default palette. The palette will persist and can be edited.
     1428        static bool saved_palette_init = true;
     1429        static ImVec4 saved_palette[32] = {};
     1430        if (saved_palette_init)
     1431        {
    8901432            for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
    8911433            {
    892                ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f, saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
    893                saved_palette[n].w = 1.0f; // Alpha
    894             }
    895          saved_palette_inited = true;
    896 
    897          static ImVec4 backup_color;
    898          bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
    899          ImGui::SameLine();
    900          open_popup |= ImGui::Button("Palette");
    901          if (open_popup)
    902          {
     1434                ImGui::ColorConvertHSVtoRGB(n / 31.0f, 0.8f, 0.8f,
     1435                    saved_palette[n].x, saved_palette[n].y, saved_palette[n].z);
     1436                saved_palette[n].w = 1.0f; // Alpha
     1437            }
     1438            saved_palette_init = false;
     1439        }
     1440
     1441        static ImVec4 backup_color;
     1442        bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
     1443        ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
     1444        open_popup |= ImGui::Button("Palette");
     1445        if (open_popup)
     1446        {
    9031447            ImGui::OpenPopup("mypicker");
    9041448            backup_color = color;
    905          }
    906          if (ImGui::BeginPopup("mypicker"))
    907          {
    908             // FIXME: Adding a drag and drop example here would be perfect!
     1449        }
     1450        if (ImGui::BeginPopup("mypicker"))
     1451        {
    9091452            ImGui::Text("MY CUSTOM COLOR PICKER WITH AN AMAZING PALETTE!");
    9101453            ImGui::Separator();
    9111454            ImGui::ColorPicker4("##picker", (float*)&color, misc_flags | ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoSmallPreview);
    9121455            ImGui::SameLine();
    913             ImGui::BeginGroup();
     1456
     1457            ImGui::BeginGroup(); // Lock X position
    9141458            ImGui::Text("Current");
    9151459            ImGui::ColorButton("##current", color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40));
    9161460            ImGui::Text("Previous");
    9171461            if (ImGui::ColorButton("##previous", backup_color, ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_AlphaPreviewHalf, ImVec2(60, 40)))
    918                color = backup_color;
     1462                color = backup_color;
    9191463            ImGui::Separator();
    9201464            ImGui::Text("Palette");
    9211465            for (int n = 0; n < IM_ARRAYSIZE(saved_palette); n++)
    9221466            {
    923                ImGui::PushID(n);
    924                if ((n % 8) != 0)
    925                   ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
    926                if (ImGui::ColorButton("##palette", saved_palette[n], ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip, ImVec2(20, 20)))
    927                   color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
    928 
    929                if (ImGui::BeginDragDropTarget())
    930                {
    931                   if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
    932                      memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
    933                   if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
    934                      memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
    935                   EndDragDropTarget();
    936                }
    937 
    938                ImGui::PopID();
     1467                ImGui::PushID(n);
     1468                if ((n % 8) != 0)
     1469                    ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
     1470
     1471                ImGuiColorEditFlags palette_button_flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoTooltip;
     1472                if (ImGui::ColorButton("##palette", saved_palette[n], palette_button_flags, ImVec2(20, 20)))
     1473                    color = ImVec4(saved_palette[n].x, saved_palette[n].y, saved_palette[n].z, color.w); // Preserve alpha!
     1474
     1475                // Allow user to drop colors into each palette entry. Note that ColorButton() is already a
     1476                // drag source by default, unless specifying the ImGuiColorEditFlags_NoDragDrop flag.
     1477                if (ImGui::BeginDragDropTarget())
     1478                {
     1479                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
     1480                        memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 3);
     1481                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
     1482                        memcpy((float*)&saved_palette[n], payload->Data, sizeof(float) * 4);
     1483                    ImGui::EndDragDropTarget();
     1484                }
     1485
     1486                ImGui::PopID();
    9391487            }
    9401488            ImGui::EndGroup();
    9411489            ImGui::EndPopup();
    942          }
    943 
    944          ImGui::Text("Color button only:");
    945          ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags, ImVec2(80, 80));
    946 
    947          ImGui::Text("Color picker:");
    948          static bool alpha = true;
    949          static bool alpha_bar = true;
    950          static bool side_preview = true;
    951          static bool ref_color = false;
    952          static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
    953          static int inputs_mode = 2;
    954          static int picker_mode = 0;
    955          ImGui::Checkbox("With Alpha", &alpha);
    956          ImGui::Checkbox("With Alpha Bar", &alpha_bar);
    957          ImGui::Checkbox("With Side Preview", &side_preview);
    958          if (side_preview)
    959          {
     1490        }
     1491
     1492        ImGui::Text("Color button only:");
     1493        static bool no_border = false;
     1494        ImGui::Checkbox("ImGuiColorEditFlags_NoBorder", &no_border);
     1495        ImGui::ColorButton("MyColor##3c", *(ImVec4*)&color, misc_flags | (no_border ? ImGuiColorEditFlags_NoBorder : 0), ImVec2(80, 80));
     1496
     1497        ImGui::Text("Color picker:");
     1498        static bool alpha = true;
     1499        static bool alpha_bar = true;
     1500        static bool side_preview = true;
     1501        static bool ref_color = false;
     1502        static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
     1503        static int display_mode = 0;
     1504        static int picker_mode = 0;
     1505        ImGui::Checkbox("With Alpha", &alpha);
     1506        ImGui::Checkbox("With Alpha Bar", &alpha_bar);
     1507        ImGui::Checkbox("With Side Preview", &side_preview);
     1508        if (side_preview)
     1509        {
    9601510            ImGui::SameLine();
    9611511            ImGui::Checkbox("With Ref Color", &ref_color);
    9621512            if (ref_color)
    9631513            {
    964                ImGui::SameLine();
    965                ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
    966             }
    967          }
    968          ImGui::Combo("Inputs Mode", &inputs_mode, "All Inputs\0No Inputs\0RGB Input\0HSV Input\0HEX Input\0");
    969          ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0");
    970          ImGui::SameLine(); ShowHelpMarker("User can right-click the picker to change mode.");
    971          ImGuiColorEditFlags flags = misc_flags;
    972          if (!alpha) flags |= ImGuiColorEditFlags_NoAlpha; // This is by default if you call ColorPicker3() instead of ColorPicker4()
    973          if (alpha_bar) flags |= ImGuiColorEditFlags_AlphaBar;
    974          if (!side_preview) flags |= ImGuiColorEditFlags_NoSidePreview;
    975          if (picker_mode == 1) flags |= ImGuiColorEditFlags_PickerHueBar;
    976          if (picker_mode == 2) flags |= ImGuiColorEditFlags_PickerHueWheel;
    977          if (inputs_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;
    978          if (inputs_mode == 2) flags |= ImGuiColorEditFlags_RGB;
    979          if (inputs_mode == 3) flags |= ImGuiColorEditFlags_HSV;
    980          if (inputs_mode == 4) flags |= ImGuiColorEditFlags_HEX;
    981          ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
    982 
    983          ImGui::Text("Programmatically set defaults/options:");
    984          ImGui::SameLine(); ShowHelpMarker("SetColorEditOptions() is designed to allow you to set boot-time default.\nWe don't have Push/Pop functions because you can force options on a per-widget basis if needed, and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid encouraging you to persistently save values that aren't forward-compatible.");
    985          if (ImGui::Button("Uint8 + HSV"))
    986             ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_HSV);
    987          ImGui::SameLine();
    988          if (ImGui::Button("Float + HDR"))
    989             ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_RGB);
    990 
    991          ImGui::TreePop();
    992       }
    993 
    994       if (ImGui::TreeNode("Range Widgets"))
    995       {
    996          static float begin = 10, end = 90;
    997          static int begin_i = 100, end_i = 1000;
    998          ImGui::DragFloatRange2("range", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%");
    999          ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %.0f units", "Max: %.0f units");
    1000          ImGui::TreePop();
    1001       }
    1002 
    1003       if (ImGui::TreeNode("Multi-component Widgets"))
    1004       {
    1005          static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
    1006          static int vec4i[4] = { 1, 5, 100, 255 };
    1007 
    1008          ImGui::InputFloat2("input float2", vec4f);
    1009          ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
    1010          ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
    1011          ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
    1012          ImGui::InputInt2("input int2", vec4i);
    1013          ImGui::SliderInt2("slider int2", vec4i, 0, 255);
    1014          ImGui::Spacing();
    1015 
    1016          ImGui::InputFloat3("input float3", vec4f);
    1017          ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
    1018          ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
    1019          ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
    1020          ImGui::InputInt3("input int3", vec4i);
    1021          ImGui::SliderInt3("slider int3", vec4i, 0, 255);
    1022          ImGui::Spacing();
    1023 
    1024          ImGui::InputFloat4("input float4", vec4f);
    1025          ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
    1026          ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
    1027          ImGui::InputInt4("input int4", vec4i);
    1028          ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
    1029          ImGui::SliderInt4("slider int4", vec4i, 0, 255);
    1030 
    1031          ImGui::TreePop();
    1032       }
    1033 
    1034       if (ImGui::TreeNode("Vertical Sliders"))
    1035       {
    1036          const float spacing = 4;
    1037          ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
    1038 
    1039          static int int_value = 0;
    1040          ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
    1041          ImGui::SameLine();
    1042 
    1043          static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
    1044          ImGui::PushID("set1");
    1045          for (int i = 0; i < 7; i++)
    1046          {
     1514                ImGui::SameLine();
     1515                ImGui::ColorEdit4("##RefColor", &ref_color_v.x, ImGuiColorEditFlags_NoInputs | misc_flags);
     1516            }
     1517        }
     1518        ImGui::Combo("Display Mode", &display_mode, "Auto/Current\0None\0RGB Only\0HSV Only\0Hex Only\0");
     1519        ImGui::SameLine(); HelpMarker(
     1520            "ColorEdit defaults to displaying RGB inputs if you don't specify a display mode, "
     1521            "but the user can change it with a right-click.\n\nColorPicker defaults to displaying RGB+HSV+Hex "
     1522            "if you don't specify a display mode.\n\nYou can change the defaults using SetColorEditOptions().");
     1523        ImGui::Combo("Picker Mode", &picker_mode, "Auto/Current\0Hue bar + SV rect\0Hue wheel + SV triangle\0");
     1524        ImGui::SameLine(); HelpMarker("User can right-click the picker to change mode.");
     1525        ImGuiColorEditFlags flags = misc_flags;
     1526        if (!alpha)            flags |= ImGuiColorEditFlags_NoAlpha;        // This is by default if you call ColorPicker3() instead of ColorPicker4()
     1527        if (alpha_bar)         flags |= ImGuiColorEditFlags_AlphaBar;
     1528        if (!side_preview)     flags |= ImGuiColorEditFlags_NoSidePreview;
     1529        if (picker_mode == 1)  flags |= ImGuiColorEditFlags_PickerHueBar;
     1530        if (picker_mode == 2)  flags |= ImGuiColorEditFlags_PickerHueWheel;
     1531        if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;       // Disable all RGB/HSV/Hex displays
     1532        if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB;     // Override display mode
     1533        if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
     1534        if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
     1535        ImGui::ColorPicker4("MyColor##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL);
     1536
     1537        ImGui::Text("Set defaults in code:");
     1538        ImGui::SameLine(); HelpMarker(
     1539            "SetColorEditOptions() is designed to allow you to set boot-time default.\n"
     1540            "We don't have Push/Pop functions because you can force options on a per-widget basis if needed,"
     1541            "and the user can change non-forced ones with the options menu.\nWe don't have a getter to avoid"
     1542            "encouraging you to persistently save values that aren't forward-compatible.");
     1543        if (ImGui::Button("Default: Uint8 + HSV + Hue Bar"))
     1544            ImGui::SetColorEditOptions(ImGuiColorEditFlags_Uint8 | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_PickerHueBar);
     1545        if (ImGui::Button("Default: Float + HDR + Hue Wheel"))
     1546            ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
     1547
     1548        // HSV encoded support (to avoid RGB<>HSV round trips and singularities when S==0 or V==0)
     1549        static ImVec4 color_hsv(0.23f, 1.0f, 1.0f, 1.0f); // Stored as HSV!
     1550        ImGui::Spacing();
     1551        ImGui::Text("HSV encoded colors");
     1552        ImGui::SameLine(); HelpMarker(
     1553            "By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV"
     1554            "allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the"
     1555            "added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
     1556        ImGui::Text("Color widget with InputHSV:");
     1557        ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
     1558        ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
     1559        ImGui::DragFloat4("Raw HSV values", (float*)&color_hsv, 0.01f, 0.0f, 1.0f);
     1560
     1561        ImGui::TreePop();
     1562    }
     1563
     1564    if (ImGui::TreeNode("Drag/Slider Flags"))
     1565    {
     1566        // Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
     1567        static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
     1568        ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", (unsigned int*)&flags, ImGuiSliderFlags_AlwaysClamp);
     1569        ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
     1570        ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", (unsigned int*)&flags, ImGuiSliderFlags_Logarithmic);
     1571        ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
     1572        ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", (unsigned int*)&flags, ImGuiSliderFlags_NoRoundToFormat);
     1573        ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
     1574        ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", (unsigned int*)&flags, ImGuiSliderFlags_NoInput);
     1575        ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
     1576
     1577        // Drags
     1578        static float drag_f = 0.5f;
     1579        static int drag_i = 50;
     1580        ImGui::Text("Underlying float value: %f", drag_f);
     1581        ImGui::DragFloat("DragFloat (0 -> 1)", &drag_f, 0.005f, 0.0f, 1.0f, "%.3f", flags);
     1582        ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
     1583        ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
     1584        ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
     1585        ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
     1586
     1587        // Sliders
     1588        static float slider_f = 0.5f;
     1589        static int slider_i = 50;
     1590        ImGui::Text("Underlying float value: %f", slider_f);
     1591        ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags);
     1592        ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags);
     1593
     1594        ImGui::TreePop();
     1595    }
     1596
     1597    if (ImGui::TreeNode("Range Widgets"))
     1598    {
     1599        static float begin = 10, end = 90;
     1600        static int begin_i = 100, end_i = 1000;
     1601        ImGui::DragFloatRange2("range float", &begin, &end, 0.25f, 0.0f, 100.0f, "Min: %.1f %%", "Max: %.1f %%", ImGuiSliderFlags_AlwaysClamp);
     1602        ImGui::DragIntRange2("range int", &begin_i, &end_i, 5, 0, 1000, "Min: %d units", "Max: %d units");
     1603        ImGui::DragIntRange2("range int (no bounds)", &begin_i, &end_i, 5, 0, 0, "Min: %d units", "Max: %d units");
     1604        ImGui::TreePop();
     1605    }
     1606
     1607    if (ImGui::TreeNode("Data Types"))
     1608    {
     1609        // DragScalar/InputScalar/SliderScalar functions allow various data types
     1610        // - signed/unsigned
     1611        // - 8/16/32/64-bits
     1612        // - integer/float/double
     1613        // To avoid polluting the public API with all possible combinations, we use the ImGuiDataType enum
     1614        // to pass the type, and passing all arguments by pointer.
     1615        // This is the reason the test code below creates local variables to hold "zero" "one" etc. for each types.
     1616        // In practice, if you frequently use a given type that is not covered by the normal API entry points,
     1617        // you can wrap it yourself inside a 1 line function which can take typed argument as value instead of void*,
     1618        // and then pass their address to the generic function. For example:
     1619        //   bool MySliderU64(const char *label, u64* value, u64 min = 0, u64 max = 0, const char* format = "%lld")
     1620        //   {
     1621        //      return SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format);
     1622        //   }
     1623
     1624        // Setup limits (as helper variables so we can take their address, as explained above)
     1625        // Note: SliderScalar() functions have a maximum usable range of half the natural type maximum, hence the /2.
     1626        #ifndef LLONG_MIN
     1627        ImS64 LLONG_MIN = -9223372036854775807LL - 1;
     1628        ImS64 LLONG_MAX = 9223372036854775807LL;
     1629        ImU64 ULLONG_MAX = (2ULL * 9223372036854775807LL + 1);
     1630        #endif
     1631        const char    s8_zero  = 0,   s8_one  = 1,   s8_fifty  = 50, s8_min  = -128,        s8_max = 127;
     1632        const ImU8    u8_zero  = 0,   u8_one  = 1,   u8_fifty  = 50, u8_min  = 0,           u8_max = 255;
     1633        const short   s16_zero = 0,   s16_one = 1,   s16_fifty = 50, s16_min = -32768,      s16_max = 32767;
     1634        const ImU16   u16_zero = 0,   u16_one = 1,   u16_fifty = 50, u16_min = 0,           u16_max = 65535;
     1635        const ImS32   s32_zero = 0,   s32_one = 1,   s32_fifty = 50, s32_min = INT_MIN/2,   s32_max = INT_MAX/2,    s32_hi_a = INT_MAX/2 - 100,    s32_hi_b = INT_MAX/2;
     1636        const ImU32   u32_zero = 0,   u32_one = 1,   u32_fifty = 50, u32_min = 0,           u32_max = UINT_MAX/2,   u32_hi_a = UINT_MAX/2 - 100,   u32_hi_b = UINT_MAX/2;
     1637        const ImS64   s64_zero = 0,   s64_one = 1,   s64_fifty = 50, s64_min = LLONG_MIN/2, s64_max = LLONG_MAX/2,  s64_hi_a = LLONG_MAX/2 - 100,  s64_hi_b = LLONG_MAX/2;
     1638        const ImU64   u64_zero = 0,   u64_one = 1,   u64_fifty = 50, u64_min = 0,           u64_max = ULLONG_MAX/2, u64_hi_a = ULLONG_MAX/2 - 100, u64_hi_b = ULLONG_MAX/2;
     1639        const float   f32_zero = 0.f, f32_one = 1.f, f32_lo_a = -10000000000.0f, f32_hi_a = +10000000000.0f;
     1640        const double  f64_zero = 0.,  f64_one = 1.,  f64_lo_a = -1000000000000000.0, f64_hi_a = +1000000000000000.0;
     1641
     1642        // State
     1643        static char   s8_v  = 127;
     1644        static ImU8   u8_v  = 255;
     1645        static short  s16_v = 32767;
     1646        static ImU16  u16_v = 65535;
     1647        static ImS32  s32_v = -1;
     1648        static ImU32  u32_v = (ImU32)-1;
     1649        static ImS64  s64_v = -1;
     1650        static ImU64  u64_v = (ImU64)-1;
     1651        static float  f32_v = 0.123f;
     1652        static double f64_v = 90000.01234567890123456789;
     1653
     1654        const float drag_speed = 0.2f;
     1655        static bool drag_clamp = false;
     1656        ImGui::Text("Drags:");
     1657        ImGui::Checkbox("Clamp integers to 0..50", &drag_clamp);
     1658        ImGui::SameLine(); HelpMarker(
     1659            "As with every widgets in dear imgui, we never modify values unless there is a user interaction.\n"
     1660            "You can override the clamping limits by using CTRL+Click to input a value.");
     1661        ImGui::DragScalar("drag s8",        ImGuiDataType_S8,     &s8_v,  drag_speed, drag_clamp ? &s8_zero  : NULL, drag_clamp ? &s8_fifty  : NULL);
     1662        ImGui::DragScalar("drag u8",        ImGuiDataType_U8,     &u8_v,  drag_speed, drag_clamp ? &u8_zero  : NULL, drag_clamp ? &u8_fifty  : NULL, "%u ms");
     1663        ImGui::DragScalar("drag s16",       ImGuiDataType_S16,    &s16_v, drag_speed, drag_clamp ? &s16_zero : NULL, drag_clamp ? &s16_fifty : NULL);
     1664        ImGui::DragScalar("drag u16",       ImGuiDataType_U16,    &u16_v, drag_speed, drag_clamp ? &u16_zero : NULL, drag_clamp ? &u16_fifty : NULL, "%u ms");
     1665        ImGui::DragScalar("drag s32",       ImGuiDataType_S32,    &s32_v, drag_speed, drag_clamp ? &s32_zero : NULL, drag_clamp ? &s32_fifty : NULL);
     1666        ImGui::DragScalar("drag u32",       ImGuiDataType_U32,    &u32_v, drag_speed, drag_clamp ? &u32_zero : NULL, drag_clamp ? &u32_fifty : NULL, "%u ms");
     1667        ImGui::DragScalar("drag s64",       ImGuiDataType_S64,    &s64_v, drag_speed, drag_clamp ? &s64_zero : NULL, drag_clamp ? &s64_fifty : NULL);
     1668        ImGui::DragScalar("drag u64",       ImGuiDataType_U64,    &u64_v, drag_speed, drag_clamp ? &u64_zero : NULL, drag_clamp ? &u64_fifty : NULL);
     1669        ImGui::DragScalar("drag float",     ImGuiDataType_Float,  &f32_v, 0.005f,  &f32_zero, &f32_one, "%f");
     1670        ImGui::DragScalar("drag float log", ImGuiDataType_Float,  &f32_v, 0.005f,  &f32_zero, &f32_one, "%f", ImGuiSliderFlags_Logarithmic);
     1671        ImGui::DragScalar("drag double",    ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, NULL,     "%.10f grams");
     1672        ImGui::DragScalar("drag double log",ImGuiDataType_Double, &f64_v, 0.0005f, &f64_zero, &f64_one, "0 < %.10f < 1", ImGuiSliderFlags_Logarithmic);
     1673
     1674        ImGui::Text("Sliders");
     1675        ImGui::SliderScalar("slider s8 full",       ImGuiDataType_S8,     &s8_v,  &s8_min,   &s8_max,   "%d");
     1676        ImGui::SliderScalar("slider u8 full",       ImGuiDataType_U8,     &u8_v,  &u8_min,   &u8_max,   "%u");
     1677        ImGui::SliderScalar("slider s16 full",      ImGuiDataType_S16,    &s16_v, &s16_min,  &s16_max,  "%d");
     1678        ImGui::SliderScalar("slider u16 full",      ImGuiDataType_U16,    &u16_v, &u16_min,  &u16_max,  "%u");
     1679        ImGui::SliderScalar("slider s32 low",       ImGuiDataType_S32,    &s32_v, &s32_zero, &s32_fifty,"%d");
     1680        ImGui::SliderScalar("slider s32 high",      ImGuiDataType_S32,    &s32_v, &s32_hi_a, &s32_hi_b, "%d");
     1681        ImGui::SliderScalar("slider s32 full",      ImGuiDataType_S32,    &s32_v, &s32_min,  &s32_max,  "%d");
     1682        ImGui::SliderScalar("slider u32 low",       ImGuiDataType_U32,    &u32_v, &u32_zero, &u32_fifty,"%u");
     1683        ImGui::SliderScalar("slider u32 high",      ImGuiDataType_U32,    &u32_v, &u32_hi_a, &u32_hi_b, "%u");
     1684        ImGui::SliderScalar("slider u32 full",      ImGuiDataType_U32,    &u32_v, &u32_min,  &u32_max,  "%u");
     1685        ImGui::SliderScalar("slider s64 low",       ImGuiDataType_S64,    &s64_v, &s64_zero, &s64_fifty,"%I64d");
     1686        ImGui::SliderScalar("slider s64 high",      ImGuiDataType_S64,    &s64_v, &s64_hi_a, &s64_hi_b, "%I64d");
     1687        ImGui::SliderScalar("slider s64 full",      ImGuiDataType_S64,    &s64_v, &s64_min,  &s64_max,  "%I64d");
     1688        ImGui::SliderScalar("slider u64 low",       ImGuiDataType_U64,    &u64_v, &u64_zero, &u64_fifty,"%I64u ms");
     1689        ImGui::SliderScalar("slider u64 high",      ImGuiDataType_U64,    &u64_v, &u64_hi_a, &u64_hi_b, "%I64u ms");
     1690        ImGui::SliderScalar("slider u64 full",      ImGuiDataType_U64,    &u64_v, &u64_min,  &u64_max,  "%I64u ms");
     1691        ImGui::SliderScalar("slider float low",     ImGuiDataType_Float,  &f32_v, &f32_zero, &f32_one);
     1692        ImGui::SliderScalar("slider float low log", ImGuiDataType_Float,  &f32_v, &f32_zero, &f32_one,  "%.10f", ImGuiSliderFlags_Logarithmic);
     1693        ImGui::SliderScalar("slider float high",    ImGuiDataType_Float,  &f32_v, &f32_lo_a, &f32_hi_a, "%e");
     1694        ImGui::SliderScalar("slider double low",    ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one,  "%.10f grams");
     1695        ImGui::SliderScalar("slider double low log",ImGuiDataType_Double, &f64_v, &f64_zero, &f64_one,  "%.10f", ImGuiSliderFlags_Logarithmic);
     1696        ImGui::SliderScalar("slider double high",   ImGuiDataType_Double, &f64_v, &f64_lo_a, &f64_hi_a, "%e grams");
     1697
     1698        ImGui::Text("Sliders (reverse)");
     1699        ImGui::SliderScalar("slider s8 reverse",    ImGuiDataType_S8,   &s8_v,  &s8_max,    &s8_min, "%d");
     1700        ImGui::SliderScalar("slider u8 reverse",    ImGuiDataType_U8,   &u8_v,  &u8_max,    &u8_min, "%u");
     1701        ImGui::SliderScalar("slider s32 reverse",   ImGuiDataType_S32,  &s32_v, &s32_fifty, &s32_zero, "%d");
     1702        ImGui::SliderScalar("slider u32 reverse",   ImGuiDataType_U32,  &u32_v, &u32_fifty, &u32_zero, "%u");
     1703        ImGui::SliderScalar("slider s64 reverse",   ImGuiDataType_S64,  &s64_v, &s64_fifty, &s64_zero, "%I64d");
     1704        ImGui::SliderScalar("slider u64 reverse",   ImGuiDataType_U64,  &u64_v, &u64_fifty, &u64_zero, "%I64u ms");
     1705
     1706        static bool inputs_step = true;
     1707        ImGui::Text("Inputs");
     1708        ImGui::Checkbox("Show step buttons", &inputs_step);
     1709        ImGui::InputScalar("input s8",      ImGuiDataType_S8,     &s8_v,  inputs_step ? &s8_one  : NULL, NULL, "%d");
     1710        ImGui::InputScalar("input u8",      ImGuiDataType_U8,     &u8_v,  inputs_step ? &u8_one  : NULL, NULL, "%u");
     1711        ImGui::InputScalar("input s16",     ImGuiDataType_S16,    &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d");
     1712        ImGui::InputScalar("input u16",     ImGuiDataType_U16,    &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u");
     1713        ImGui::InputScalar("input s32",     ImGuiDataType_S32,    &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d");
     1714        ImGui::InputScalar("input s32 hex", ImGuiDataType_S32,    &s32_v, inputs_step ? &s32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
     1715        ImGui::InputScalar("input u32",     ImGuiDataType_U32,    &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u");
     1716        ImGui::InputScalar("input u32 hex", ImGuiDataType_U32,    &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
     1717        ImGui::InputScalar("input s64",     ImGuiDataType_S64,    &s64_v, inputs_step ? &s64_one : NULL);
     1718        ImGui::InputScalar("input u64",     ImGuiDataType_U64,    &u64_v, inputs_step ? &u64_one : NULL);
     1719        ImGui::InputScalar("input float",   ImGuiDataType_Float,  &f32_v, inputs_step ? &f32_one : NULL);
     1720        ImGui::InputScalar("input double",  ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL);
     1721
     1722        ImGui::TreePop();
     1723    }
     1724
     1725    if (ImGui::TreeNode("Multi-component Widgets"))
     1726    {
     1727        static float vec4f[4] = { 0.10f, 0.20f, 0.30f, 0.44f };
     1728        static int vec4i[4] = { 1, 5, 100, 255 };
     1729
     1730        ImGui::InputFloat2("input float2", vec4f);
     1731        ImGui::DragFloat2("drag float2", vec4f, 0.01f, 0.0f, 1.0f);
     1732        ImGui::SliderFloat2("slider float2", vec4f, 0.0f, 1.0f);
     1733        ImGui::InputInt2("input int2", vec4i);
     1734        ImGui::DragInt2("drag int2", vec4i, 1, 0, 255);
     1735        ImGui::SliderInt2("slider int2", vec4i, 0, 255);
     1736        ImGui::Spacing();
     1737
     1738        ImGui::InputFloat3("input float3", vec4f);
     1739        ImGui::DragFloat3("drag float3", vec4f, 0.01f, 0.0f, 1.0f);
     1740        ImGui::SliderFloat3("slider float3", vec4f, 0.0f, 1.0f);
     1741        ImGui::InputInt3("input int3", vec4i);
     1742        ImGui::DragInt3("drag int3", vec4i, 1, 0, 255);
     1743        ImGui::SliderInt3("slider int3", vec4i, 0, 255);
     1744        ImGui::Spacing();
     1745
     1746        ImGui::InputFloat4("input float4", vec4f);
     1747        ImGui::DragFloat4("drag float4", vec4f, 0.01f, 0.0f, 1.0f);
     1748        ImGui::SliderFloat4("slider float4", vec4f, 0.0f, 1.0f);
     1749        ImGui::InputInt4("input int4", vec4i);
     1750        ImGui::DragInt4("drag int4", vec4i, 1, 0, 255);
     1751        ImGui::SliderInt4("slider int4", vec4i, 0, 255);
     1752
     1753        ImGui::TreePop();
     1754    }
     1755
     1756    if (ImGui::TreeNode("Vertical Sliders"))
     1757    {
     1758        const float spacing = 4;
     1759        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing));
     1760
     1761        static int int_value = 0;
     1762        ImGui::VSliderInt("##int", ImVec2(18, 160), &int_value, 0, 5);
     1763        ImGui::SameLine();
     1764
     1765        static float values[7] = { 0.0f, 0.60f, 0.35f, 0.9f, 0.70f, 0.20f, 0.0f };
     1766        ImGui::PushID("set1");
     1767        for (int i = 0; i < 7; i++)
     1768        {
    10471769            if (i > 0) ImGui::SameLine();
    10481770            ImGui::PushID(i);
     
    10531775            ImGui::VSliderFloat("##v", ImVec2(18, 160), &values[i], 0.0f, 1.0f, "");
    10541776            if (ImGui::IsItemActive() || ImGui::IsItemHovered())
    1055                ImGui::SetTooltip("%.3f", values[i]);
     1777                ImGui::SetTooltip("%.3f", values[i]);
    10561778            ImGui::PopStyleColor(4);
    10571779            ImGui::PopID();
    1058          }
    1059          ImGui::PopID();
    1060 
    1061          ImGui::SameLine();
    1062          ImGui::PushID("set2");
    1063          static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
    1064          const int rows = 3;
    1065          const ImVec2 small_slider_size(18, (160.0f - (rows - 1)*spacing) / rows);
    1066          for (int nx = 0; nx < 4; nx++)
    1067          {
     1780        }
     1781        ImGui::PopID();
     1782
     1783        ImGui::SameLine();
     1784        ImGui::PushID("set2");
     1785        static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
     1786        const int rows = 3;
     1787        const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
     1788        for (int nx = 0; nx < 4; nx++)
     1789        {
    10681790            if (nx > 0) ImGui::SameLine();
    10691791            ImGui::BeginGroup();
    10701792            for (int ny = 0; ny < rows; ny++)
    10711793            {
    1072                ImGui::PushID(nx*rows + ny);
    1073                ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
    1074                if (ImGui::IsItemActive() || ImGui::IsItemHovered())
    1075                   ImGui::SetTooltip("%.3f", values2[nx]);
    1076                ImGui::PopID();
     1794                ImGui::PushID(nx * rows + ny);
     1795                ImGui::VSliderFloat("##v", small_slider_size, &values2[nx], 0.0f, 1.0f, "");
     1796                if (ImGui::IsItemActive() || ImGui::IsItemHovered())
     1797                    ImGui::SetTooltip("%.3f", values2[nx]);
     1798                ImGui::PopID();
    10771799            }
    10781800            ImGui::EndGroup();
    1079          }
    1080          ImGui::PopID();
    1081 
    1082          ImGui::SameLine();
    1083          ImGui::PushID("set3");
    1084          for (int i = 0; i < 4; i++)
    1085          {
     1801        }
     1802        ImGui::PopID();
     1803
     1804        ImGui::SameLine();
     1805        ImGui::PushID("set3");
     1806        for (int i = 0; i < 4; i++)
     1807        {
    10861808            if (i > 0) ImGui::SameLine();
    10871809            ImGui::PushID(i);
     
    10901812            ImGui::PopStyleVar();
    10911813            ImGui::PopID();
    1092          }
    1093          ImGui::PopID();
    1094          ImGui::PopStyleVar();
    1095          ImGui::TreePop();
    1096       }
    1097    }
    1098 
    1099    if (ImGui::CollapsingHeader("Layout"))
    1100    {
    1101       if (ImGui::TreeNode("Child regions"))
    1102       {
    1103          static bool disable_mouse_wheel = false;
    1104          static bool disable_menu = false;
    1105          ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
    1106          ImGui::Checkbox("Disable Menu", &disable_menu);
    1107 
    1108          static int line = 50;
    1109          bool goto_line = ImGui::Button("Goto");
    1110          ImGui::SameLine();
    1111          ImGui::PushItemWidth(100);
    1112          goto_line |= ImGui::InputInt("##Line", &line, 0, 0, ImGuiInputTextFlags_EnterReturnsTrue);
    1113          ImGui::PopItemWidth();
    1114 
    1115          // Child 1: no border, enable horizontal scrollbar
    1116          {
    1117             ImGui::BeginChild("Child1", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 300), false, ImGuiWindowFlags_HorizontalScrollbar | (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0));
     1814        }
     1815        ImGui::PopID();
     1816        ImGui::PopStyleVar();
     1817        ImGui::TreePop();
     1818    }
     1819
     1820    if (ImGui::TreeNode("Drag and Drop"))
     1821    {
     1822        if (ImGui::TreeNode("Drag and drop in standard widgets"))
     1823        {
     1824            // ColorEdit widgets automatically act as drag source and drag target.
     1825            // They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F
     1826            // to allow your own widgets to use colors in their drag and drop interaction.
     1827            // Also see 'Demo->Widgets->Color/Picker Widgets->Palette' demo.
     1828            HelpMarker("You can drag from the colored squares.");
     1829            static float col1[3] = { 1.0f, 0.0f, 0.2f };
     1830            static float col2[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
     1831            ImGui::ColorEdit3("color 1", col1);
     1832            ImGui::ColorEdit4("color 2", col2);
     1833            ImGui::TreePop();
     1834        }
     1835
     1836        if (ImGui::TreeNode("Drag and drop to copy/swap items"))
     1837        {
     1838            enum Mode
     1839            {
     1840                Mode_Copy,
     1841                Mode_Move,
     1842                Mode_Swap
     1843            };
     1844            static int mode = 0;
     1845            if (ImGui::RadioButton("Copy", mode == Mode_Copy)) { mode = Mode_Copy; } ImGui::SameLine();
     1846            if (ImGui::RadioButton("Move", mode == Mode_Move)) { mode = Mode_Move; } ImGui::SameLine();
     1847            if (ImGui::RadioButton("Swap", mode == Mode_Swap)) { mode = Mode_Swap; }
     1848            static const char* names[9] =
     1849            {
     1850                "Bobby", "Beatrice", "Betty",
     1851                "Brianna", "Barry", "Bernard",
     1852                "Bibi", "Blaine", "Bryn"
     1853            };
     1854            for (int n = 0; n < IM_ARRAYSIZE(names); n++)
     1855            {
     1856                ImGui::PushID(n);
     1857                if ((n % 3) != 0)
     1858                    ImGui::SameLine();
     1859                ImGui::Button(names[n], ImVec2(60, 60));
     1860
     1861                // Our buttons are both drag sources and drag targets here!
     1862                if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
     1863                {
     1864                    // Set payload to carry the index of our item (could be anything)
     1865                    ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int));
     1866
     1867                    // Display preview (could be anything, e.g. when dragging an image we could decide to display
     1868                    // the filename and a small preview of the image, etc.)
     1869                    if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); }
     1870                    if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
     1871                    if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
     1872                    ImGui::EndDragDropSource();
     1873                }
     1874                if (ImGui::BeginDragDropTarget())
     1875                {
     1876                    if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("DND_DEMO_CELL"))
     1877                    {
     1878                        IM_ASSERT(payload->DataSize == sizeof(int));
     1879                        int payload_n = *(const int*)payload->Data;
     1880                        if (mode == Mode_Copy)
     1881                        {
     1882                            names[n] = names[payload_n];
     1883                        }
     1884                        if (mode == Mode_Move)
     1885                        {
     1886                            names[n] = names[payload_n];
     1887                            names[payload_n] = "";
     1888                        }
     1889                        if (mode == Mode_Swap)
     1890                        {
     1891                            const char* tmp = names[n];
     1892                            names[n] = names[payload_n];
     1893                            names[payload_n] = tmp;
     1894                        }
     1895                    }
     1896                    ImGui::EndDragDropTarget();
     1897                }
     1898                ImGui::PopID();
     1899            }
     1900            ImGui::TreePop();
     1901        }
     1902
     1903        if (ImGui::TreeNode("Drag to reorder items (simple)"))
     1904        {
     1905            // Simple reordering
     1906            HelpMarker(
     1907                "We don't use the drag and drop api at all here! "
     1908                "Instead we query when the item is held but not hovered, and order items accordingly.");
     1909            static const char* item_names[] = { "Item One", "Item Two", "Item Three", "Item Four", "Item Five" };
     1910            for (int n = 0; n < IM_ARRAYSIZE(item_names); n++)
     1911            {
     1912                const char* item = item_names[n];
     1913                ImGui::Selectable(item);
     1914
     1915                if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
     1916                {
     1917                    int n_next = n + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
     1918                    if (n_next >= 0 && n_next < IM_ARRAYSIZE(item_names))
     1919                    {
     1920                        item_names[n] = item_names[n_next];
     1921                        item_names[n_next] = item;
     1922                        ImGui::ResetMouseDragDelta();
     1923                    }
     1924                }
     1925            }
     1926            ImGui::TreePop();
     1927        }
     1928
     1929        ImGui::TreePop();
     1930    }
     1931
     1932    if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)"))
     1933    {
     1934        // Select an item type
     1935        const char* item_names[] =
     1936        {
     1937            "Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat",
     1938            "InputFloat3", "ColorEdit4", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "ListBox"
     1939        };
     1940        static int item_type = 1;
     1941        ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
     1942        ImGui::SameLine();
     1943        HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions.");
     1944
     1945        // Submit selected item item so we can query their status in the code following it.
     1946        bool ret = false;
     1947        static bool b = false;
     1948        static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
     1949        static char str[16] = {};
     1950        if (item_type == 0) { ImGui::Text("ITEM: Text"); }                                              // Testing text items with no identifier/interaction
     1951        if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); }                                    // Testing button
     1952        if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
     1953        if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); }                            // Testing checkbox
     1954        if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); }   // Testing basic item
     1955        if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); }  // Testing input text (which handles tabbing)
     1956        if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); }               // Testing +/- buttons on scalar input
     1957        if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); }                   // Testing multi-component items (IsItemXXX flags are reported merged)
     1958        if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); }                     // Testing multi-component items (IsItemXXX flags are reported merged)
     1959        if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); }                                // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
     1960        if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); }     // Testing tree node
     1961        if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
     1962        if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
     1963
     1964        // Display the values of IsItemHovered() and other common item state functions.
     1965        // Note that the ImGuiHoveredFlags_XXX flags can be combined.
     1966        // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
     1967        // we query every state in a single call to avoid storing them and to simplify the code.
     1968        ImGui::BulletText(
     1969            "Return value = %d\n"
     1970            "IsItemFocused() = %d\n"
     1971            "IsItemHovered() = %d\n"
     1972            "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
     1973            "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
     1974            "IsItemHovered(_AllowWhenOverlapped) = %d\n"
     1975            "IsItemHovered(_RectOnly) = %d\n"
     1976            "IsItemActive() = %d\n"
     1977            "IsItemEdited() = %d\n"
     1978            "IsItemActivated() = %d\n"
     1979            "IsItemDeactivated() = %d\n"
     1980            "IsItemDeactivatedAfterEdit() = %d\n"
     1981            "IsItemVisible() = %d\n"
     1982            "IsItemClicked() = %d\n"
     1983            "IsItemToggledOpen() = %d\n"
     1984            "GetItemRectMin() = (%.1f, %.1f)\n"
     1985            "GetItemRectMax() = (%.1f, %.1f)\n"
     1986            "GetItemRectSize() = (%.1f, %.1f)",
     1987            ret,
     1988            ImGui::IsItemFocused(),
     1989            ImGui::IsItemHovered(),
     1990            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
     1991            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
     1992            ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped),
     1993            ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly),
     1994            ImGui::IsItemActive(),
     1995            ImGui::IsItemEdited(),
     1996            ImGui::IsItemActivated(),
     1997            ImGui::IsItemDeactivated(),
     1998            ImGui::IsItemDeactivatedAfterEdit(),
     1999            ImGui::IsItemVisible(),
     2000            ImGui::IsItemClicked(),
     2001            ImGui::IsItemToggledOpen(),
     2002            ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
     2003            ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
     2004            ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y
     2005        );
     2006
     2007        static bool embed_all_inside_a_child_window = false;
     2008        ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window);
     2009        if (embed_all_inside_a_child_window)
     2010            ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), true);
     2011
     2012        // Testing IsWindowFocused() function with its various flags.
     2013        // Note that the ImGuiFocusedFlags_XXX flags can be combined.
     2014        ImGui::BulletText(
     2015            "IsWindowFocused() = %d\n"
     2016            "IsWindowFocused(_ChildWindows) = %d\n"
     2017            "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
     2018            "IsWindowFocused(_RootWindow) = %d\n"
     2019            "IsWindowFocused(_AnyWindow) = %d\n",
     2020            ImGui::IsWindowFocused(),
     2021            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
     2022            ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
     2023            ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
     2024            ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
     2025
     2026        // Testing IsWindowHovered() function with its various flags.
     2027        // Note that the ImGuiHoveredFlags_XXX flags can be combined.
     2028        ImGui::BulletText(
     2029            "IsWindowHovered() = %d\n"
     2030            "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
     2031            "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
     2032            "IsWindowHovered(_ChildWindows) = %d\n"
     2033            "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
     2034            "IsWindowHovered(_ChildWindows|_AllowWhenBlockedByPopup) = %d\n"
     2035            "IsWindowHovered(_RootWindow) = %d\n"
     2036            "IsWindowHovered(_AnyWindow) = %d\n",
     2037            ImGui::IsWindowHovered(),
     2038            ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
     2039            ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
     2040            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
     2041            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
     2042            ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup),
     2043            ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
     2044            ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow));
     2045
     2046        ImGui::BeginChild("child", ImVec2(0, 50), true);
     2047        ImGui::Text("This is another child window for testing the _ChildWindows flag.");
     2048        ImGui::EndChild();
     2049        if (embed_all_inside_a_child_window)
     2050            ImGui::EndChild();
     2051
     2052        static char unused_str[] = "This widget is only here to be able to tab-out of the widgets above.";
     2053        ImGui::InputText("unused", unused_str, IM_ARRAYSIZE(unused_str), ImGuiInputTextFlags_ReadOnly);
     2054
     2055        // Calling IsItemHovered() after begin returns the hovered status of the title bar.
     2056        // This is useful in particular if you want to create a context menu associated to the title bar of a window.
     2057        static bool test_window = false;
     2058        ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
     2059        if (test_window)
     2060        {
     2061            ImGui::Begin("Title bar Hovered/Active tests", &test_window);
     2062            if (ImGui::BeginPopupContextItem()) // <-- This is using IsItemHovered()
     2063            {
     2064                if (ImGui::MenuItem("Close")) { test_window = false; }
     2065                ImGui::EndPopup();
     2066            }
     2067            ImGui::Text(
     2068                "IsItemHovered() after begin = %d (== is title bar hovered)\n"
     2069                "IsItemActive() after begin = %d (== is window being clicked/moved)\n",
     2070                ImGui::IsItemHovered(), ImGui::IsItemActive());
     2071            ImGui::End();
     2072        }
     2073
     2074        ImGui::TreePop();
     2075    }
     2076}
     2077
     2078static void ShowDemoWindowLayout()
     2079{
     2080    if (!ImGui::CollapsingHeader("Layout & Scrolling"))
     2081        return;
     2082
     2083    if (ImGui::TreeNode("Child windows"))
     2084    {
     2085        HelpMarker("Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window.");
     2086        static bool disable_mouse_wheel = false;
     2087        static bool disable_menu = false;
     2088        ImGui::Checkbox("Disable Mouse Wheel", &disable_mouse_wheel);
     2089        ImGui::Checkbox("Disable Menu", &disable_menu);
     2090
     2091        // Child 1: no border, enable horizontal scrollbar
     2092        {
     2093            ImGuiWindowFlags window_flags = ImGuiWindowFlags_HorizontalScrollbar;
     2094            if (disable_mouse_wheel)
     2095                window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
     2096            ImGui::BeginChild("ChildL", ImVec2(ImGui::GetWindowContentRegionWidth() * 0.5f, 260), false, window_flags);
    11182097            for (int i = 0; i < 100; i++)
    1119             {
    1120                ImGui::Text("%04d: scrollable region", i);
    1121                if (goto_line && line == i)
    1122                   ImGui::SetScrollHere();
    1123             }
    1124             if (goto_line && line >= 100)
    1125                ImGui::SetScrollHere();
     2098                ImGui::Text("%04d: scrollable region", i);
    11262099            ImGui::EndChild();
    1127          }
    1128 
    1129          ImGui::SameLine();
    1130 
    1131          // Child 2: rounded border
    1132          {
     2100        }
     2101
     2102        ImGui::SameLine();
     2103
     2104        // Child 2: rounded border
     2105        {
     2106            ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
     2107            if (disable_mouse_wheel)
     2108                window_flags |= ImGuiWindowFlags_NoScrollWithMouse;
     2109            if (!disable_menu)
     2110                window_flags |= ImGuiWindowFlags_MenuBar;
    11332111            ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
    1134             ImGui::BeginChild("Child2", ImVec2(0, 300), true, (disable_mouse_wheel ? ImGuiWindowFlags_NoScrollWithMouse : 0) | (disable_menu ? 0 : ImGuiWindowFlags_MenuBar));
     2112            ImGui::BeginChild("ChildR", ImVec2(0, 260), true, window_flags);
    11352113            if (!disable_menu && ImGui::BeginMenuBar())
    11362114            {
    1137                if (ImGui::BeginMenu("Menu"))
    1138                {
    1139                   ShowExampleMenuFile();
    1140                   ImGui::EndMenu();
    1141                }
    1142                ImGui::EndMenuBar();
     2115                if (ImGui::BeginMenu("Menu"))
     2116                {
     2117                    ShowExampleMenuFile();
     2118                    ImGui::EndMenu();
     2119                }
     2120                ImGui::EndMenuBar();
    11432121            }
    11442122            ImGui::Columns(2);
    11452123            for (int i = 0; i < 100; i++)
    11462124            {
    1147                if (i == 50)
    1148                   ImGui::NextColumn();
    1149                char buf[32];
    1150                sprintf(buf, "%08x", i * 5731);
    1151                ImGui::Button(buf, ImVec2(-1.0f, 0.0f));
     2125                char buf[32];
     2126                sprintf(buf, "%03d", i);
     2127                ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
     2128                ImGui::NextColumn();
    11522129            }
    11532130            ImGui::EndChild();
    11542131            ImGui::PopStyleVar();
    1155          }
    1156 
    1157          ImGui::TreePop();
    1158       }
    1159 
    1160       if (ImGui::TreeNode("Widgets Width"))
    1161       {
    1162          static float f = 0.0f;
    1163          ImGui::Text("PushItemWidth(100)");
    1164          ImGui::SameLine(); ShowHelpMarker("Fixed width.");
    1165          ImGui::PushItemWidth(100);
    1166          ImGui::DragFloat("float##1", &f);
    1167          ImGui::PopItemWidth();
    1168 
    1169          ImGui::Text("PushItemWidth(GetWindowWidth() * 0.5f)");
    1170          ImGui::SameLine(); ShowHelpMarker("Half of window width.");
    1171          ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
    1172          ImGui::DragFloat("float##2", &f);
    1173          ImGui::PopItemWidth();
    1174 
    1175          ImGui::Text("PushItemWidth(GetContentRegionAvailWidth() * 0.5f)");
    1176          ImGui::SameLine(); ShowHelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
    1177          ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth() * 0.5f);
    1178          ImGui::DragFloat("float##3", &f);
    1179          ImGui::PopItemWidth();
    1180 
    1181          ImGui::Text("PushItemWidth(-100)");
    1182          ImGui::SameLine(); ShowHelpMarker("Align to right edge minus 100");
    1183          ImGui::PushItemWidth(-100);
    1184          ImGui::DragFloat("float##4", &f);
    1185          ImGui::PopItemWidth();
    1186 
    1187          ImGui::Text("PushItemWidth(-1)");
    1188          ImGui::SameLine(); ShowHelpMarker("Align to right edge");
    1189          ImGui::PushItemWidth(-1);
    1190          ImGui::DragFloat("float##5", &f);
    1191          ImGui::PopItemWidth();
    1192 
    1193          ImGui::TreePop();
    1194       }
    1195 
    1196       if (ImGui::TreeNode("Basic Horizontal Layout"))
    1197       {
    1198          ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
    1199 
    1200          // Text
    1201          ImGui::Text("Two items: Hello"); ImGui::SameLine();
    1202          ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
    1203 
    1204          // Adjust spacing
    1205          ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
    1206          ImGui::TextColored(ImVec4(1, 1, 0, 1), "Sailor");
    1207 
    1208          // Button
    1209          ImGui::AlignTextToFramePadding();
    1210          ImGui::Text("Normal buttons"); ImGui::SameLine();
    1211          ImGui::Button("Banana"); ImGui::SameLine();
    1212          ImGui::Button("Apple"); ImGui::SameLine();
    1213          ImGui::Button("Corniflower");
    1214 
    1215          // Button
    1216          ImGui::Text("Small buttons"); ImGui::SameLine();
    1217          ImGui::SmallButton("Like this one"); ImGui::SameLine();
    1218          ImGui::Text("can fit within a text block.");
    1219 
    1220          // Aligned to arbitrary position. Easy/cheap column.
    1221          ImGui::Text("Aligned");
    1222          ImGui::SameLine(150); ImGui::Text("x=150");
    1223          ImGui::SameLine(300); ImGui::Text("x=300");
    1224          ImGui::Text("Aligned");
    1225          ImGui::SameLine(150); ImGui::SmallButton("x=150");
    1226          ImGui::SameLine(300); ImGui::SmallButton("x=300");
    1227 
    1228          // Checkbox
    1229          static bool c1 = false, c2 = false, c3 = false, c4 = false;
    1230          ImGui::Checkbox("My", &c1); ImGui::SameLine();
    1231          ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
    1232          ImGui::Checkbox("Is", &c3); ImGui::SameLine();
    1233          ImGui::Checkbox("Rich", &c4);
    1234 
    1235          // Various
    1236          static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
    1237          ImGui::PushItemWidth(80);
    1238          const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
    1239          static int item = -1;
    1240          ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
    1241          ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
    1242          ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
    1243          ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
    1244          ImGui::PopItemWidth();
    1245 
    1246          ImGui::PushItemWidth(80);
    1247          ImGui::Text("Lists:");
    1248          static int selection[4] = { 0, 1, 2, 3 };
    1249          for (int i = 0; i < 4; i++)
    1250          {
     2132        }
     2133
     2134        ImGui::Separator();
     2135
     2136        // Demonstrate a few extra things
     2137        // - Changing ImGuiCol_ChildBg (which is transparent black in default styles)
     2138        // - Using SetCursorPos() to position child window (the child window is an item from the POV of parent window)
     2139        //   You can also call SetNextWindowPos() to position the child window. The parent window will effectively
     2140        //   layout from this position.
     2141        // - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from
     2142        //   the POV of the parent window). See 'Demo->Querying Status (Active/Focused/Hovered etc.)' for details.
     2143        {
     2144            static int offset_x = 0;
     2145            ImGui::SetNextItemWidth(100);
     2146            ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
     2147
     2148            ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (float)offset_x);
     2149            ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
     2150            ImGui::BeginChild("Red", ImVec2(200, 100), true, ImGuiWindowFlags_None);
     2151            for (int n = 0; n < 50; n++)
     2152                ImGui::Text("Some test %d", n);
     2153            ImGui::EndChild();
     2154            bool child_is_hovered = ImGui::IsItemHovered();
     2155            ImVec2 child_rect_min = ImGui::GetItemRectMin();
     2156            ImVec2 child_rect_max = ImGui::GetItemRectMax();
     2157            ImGui::PopStyleColor();
     2158            ImGui::Text("Hovered: %d", child_is_hovered);
     2159            ImGui::Text("Rect of child window is: (%.0f,%.0f) (%.0f,%.0f)", child_rect_min.x, child_rect_min.y, child_rect_max.x, child_rect_max.y);
     2160        }
     2161
     2162        ImGui::TreePop();
     2163    }
     2164
     2165    if (ImGui::TreeNode("Widgets Width"))
     2166    {
     2167        // Use SetNextItemWidth() to set the width of a single upcoming item.
     2168        // Use PushItemWidth()/PopItemWidth() to set the width of a group of items.
     2169        // In real code use you'll probably want to choose width values that are proportional to your font size
     2170        // e.g. Using '20.0f * GetFontSize()' as width instead of '200.0f', etc.
     2171
     2172        static float f = 0.0f;
     2173        ImGui::Text("SetNextItemWidth/PushItemWidth(100)");
     2174        ImGui::SameLine(); HelpMarker("Fixed width.");
     2175        ImGui::SetNextItemWidth(100);
     2176        ImGui::DragFloat("float##1", &f);
     2177
     2178        ImGui::Text("SetNextItemWidth/PushItemWidth(GetWindowWidth() * 0.5f)");
     2179        ImGui::SameLine(); HelpMarker("Half of window width.");
     2180        ImGui::SetNextItemWidth(ImGui::GetWindowWidth() * 0.5f);
     2181        ImGui::DragFloat("float##2", &f);
     2182
     2183        ImGui::Text("SetNextItemWidth/PushItemWidth(GetContentRegionAvail().x * 0.5f)");
     2184        ImGui::SameLine(); HelpMarker("Half of available width.\n(~ right-cursor_pos)\n(works within a column set)");
     2185        ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.5f);
     2186        ImGui::DragFloat("float##3", &f);
     2187
     2188        ImGui::Text("SetNextItemWidth/PushItemWidth(-100)");
     2189        ImGui::SameLine(); HelpMarker("Align to right edge minus 100");
     2190        ImGui::SetNextItemWidth(-100);
     2191        ImGui::DragFloat("float##4", &f);
     2192
     2193        // Demonstrate using PushItemWidth to surround three items.
     2194        // Calling SetNextItemWidth() before each of them would have the same effect.
     2195        ImGui::Text("SetNextItemWidth/PushItemWidth(-1)");
     2196        ImGui::SameLine(); HelpMarker("Align to right edge");
     2197        ImGui::PushItemWidth(-1);
     2198        ImGui::DragFloat("##float5a", &f);
     2199        ImGui::DragFloat("##float5b", &f);
     2200        ImGui::DragFloat("##float5c", &f);
     2201        ImGui::PopItemWidth();
     2202
     2203        ImGui::TreePop();
     2204    }
     2205
     2206    if (ImGui::TreeNode("Basic Horizontal Layout"))
     2207    {
     2208        ImGui::TextWrapped("(Use ImGui::SameLine() to keep adding items to the right of the preceding item)");
     2209
     2210        // Text
     2211        ImGui::Text("Two items: Hello"); ImGui::SameLine();
     2212        ImGui::TextColored(ImVec4(1,1,0,1), "Sailor");
     2213
     2214        // Adjust spacing
     2215        ImGui::Text("More spacing: Hello"); ImGui::SameLine(0, 20);
     2216        ImGui::TextColored(ImVec4(1,1,0,1), "Sailor");
     2217
     2218        // Button
     2219        ImGui::AlignTextToFramePadding();
     2220        ImGui::Text("Normal buttons"); ImGui::SameLine();
     2221        ImGui::Button("Banana"); ImGui::SameLine();
     2222        ImGui::Button("Apple"); ImGui::SameLine();
     2223        ImGui::Button("Corniflower");
     2224
     2225        // Button
     2226        ImGui::Text("Small buttons"); ImGui::SameLine();
     2227        ImGui::SmallButton("Like this one"); ImGui::SameLine();
     2228        ImGui::Text("can fit within a text block.");
     2229
     2230        // Aligned to arbitrary position. Easy/cheap column.
     2231        ImGui::Text("Aligned");
     2232        ImGui::SameLine(150); ImGui::Text("x=150");
     2233        ImGui::SameLine(300); ImGui::Text("x=300");
     2234        ImGui::Text("Aligned");
     2235        ImGui::SameLine(150); ImGui::SmallButton("x=150");
     2236        ImGui::SameLine(300); ImGui::SmallButton("x=300");
     2237
     2238        // Checkbox
     2239        static bool c1 = false, c2 = false, c3 = false, c4 = false;
     2240        ImGui::Checkbox("My", &c1); ImGui::SameLine();
     2241        ImGui::Checkbox("Tailor", &c2); ImGui::SameLine();
     2242        ImGui::Checkbox("Is", &c3); ImGui::SameLine();
     2243        ImGui::Checkbox("Rich", &c4);
     2244
     2245        // Various
     2246        static float f0 = 1.0f, f1 = 2.0f, f2 = 3.0f;
     2247        ImGui::PushItemWidth(80);
     2248        const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD" };
     2249        static int item = -1;
     2250        ImGui::Combo("Combo", &item, items, IM_ARRAYSIZE(items)); ImGui::SameLine();
     2251        ImGui::SliderFloat("X", &f0, 0.0f, 5.0f); ImGui::SameLine();
     2252        ImGui::SliderFloat("Y", &f1, 0.0f, 5.0f); ImGui::SameLine();
     2253        ImGui::SliderFloat("Z", &f2, 0.0f, 5.0f);
     2254        ImGui::PopItemWidth();
     2255
     2256        ImGui::PushItemWidth(80);
     2257        ImGui::Text("Lists:");
     2258        static int selection[4] = { 0, 1, 2, 3 };
     2259        for (int i = 0; i < 4; i++)
     2260        {
    12512261            if (i > 0) ImGui::SameLine();
    12522262            ImGui::PushID(i);
     
    12542264            ImGui::PopID();
    12552265            //if (ImGui::IsItemHovered()) ImGui::SetTooltip("ListBox %d hovered", i);
    1256          }
    1257          ImGui::PopItemWidth();
    1258 
    1259          // Dummy
    1260          ImVec2 sz(30, 30);
    1261          ImGui::Button("A", sz); ImGui::SameLine();
    1262          ImGui::Dummy(sz); ImGui::SameLine();
    1263          ImGui::Button("B", sz);
    1264 
    1265          ImGui::TreePop();
    1266       }
    1267 
    1268       if (ImGui::TreeNode("Groups"))
    1269       {
    1270          ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)");
    1271          ImGui::BeginGroup();
    1272          {
     2266        }
     2267        ImGui::PopItemWidth();
     2268
     2269        // Dummy
     2270        ImVec2 button_sz(40, 40);
     2271        ImGui::Button("A", button_sz); ImGui::SameLine();
     2272        ImGui::Dummy(button_sz); ImGui::SameLine();
     2273        ImGui::Button("B", button_sz);
     2274
     2275        // Manually wrapping
     2276        // (we should eventually provide this as an automatic layout feature, but for now you can do it manually)
     2277        ImGui::Text("Manually wrapping:");
     2278        ImGuiStyle& style = ImGui::GetStyle();
     2279        int buttons_count = 20;
     2280        float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
     2281        for (int n = 0; n < buttons_count; n++)
     2282        {
     2283            ImGui::PushID(n);
     2284            ImGui::Button("Box", button_sz);
     2285            float last_button_x2 = ImGui::GetItemRectMax().x;
     2286            float next_button_x2 = last_button_x2 + style.ItemSpacing.x + button_sz.x; // Expected position if next button was on same line
     2287            if (n + 1 < buttons_count && next_button_x2 < window_visible_x2)
     2288                ImGui::SameLine();
     2289            ImGui::PopID();
     2290        }
     2291
     2292        ImGui::TreePop();
     2293    }
     2294
     2295    if (ImGui::TreeNode("Tabs"))
     2296    {
     2297        if (ImGui::TreeNode("Basic"))
     2298        {
     2299            ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
     2300            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
     2301            {
     2302                if (ImGui::BeginTabItem("Avocado"))
     2303                {
     2304                    ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
     2305                    ImGui::EndTabItem();
     2306                }
     2307                if (ImGui::BeginTabItem("Broccoli"))
     2308                {
     2309                    ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
     2310                    ImGui::EndTabItem();
     2311                }
     2312                if (ImGui::BeginTabItem("Cucumber"))
     2313                {
     2314                    ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
     2315                    ImGui::EndTabItem();
     2316                }
     2317                ImGui::EndTabBar();
     2318            }
     2319            ImGui::Separator();
     2320            ImGui::TreePop();
     2321        }
     2322
     2323        if (ImGui::TreeNode("Advanced & Close Button"))
     2324        {
     2325            // Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
     2326            static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
     2327            ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable);
     2328            ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
     2329            ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
     2330            ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
     2331            if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
     2332                tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
     2333            if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
     2334                tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
     2335            if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
     2336                tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
     2337
     2338            // Tab Bar
     2339            const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
     2340            static bool opened[4] = { true, true, true, true }; // Persistent user state
     2341            for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
     2342            {
     2343                if (n > 0) { ImGui::SameLine(); }
     2344                ImGui::Checkbox(names[n], &opened[n]);
     2345            }
     2346
     2347            // Passing a bool* to BeginTabItem() is similar to passing one to Begin():
     2348            // the underlying bool will be set to false when the tab is closed.
     2349            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
     2350            {
     2351                for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
     2352                    if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n], ImGuiTabItemFlags_None))
     2353                    {
     2354                        ImGui::Text("This is the %s tab!", names[n]);
     2355                        if (n & 1)
     2356                            ImGui::Text("I am an odd tab.");
     2357                        ImGui::EndTabItem();
     2358                    }
     2359                ImGui::EndTabBar();
     2360            }
     2361            ImGui::Separator();
     2362            ImGui::TreePop();
     2363        }
     2364
     2365        if (ImGui::TreeNode("TabItemButton & Leading/Trailing flags"))
     2366        {
     2367            static ImVector<int> active_tabs;
     2368            static int next_tab_id = 0;
     2369            if (next_tab_id == 0) // Initialize with some default tabs
     2370                for (int i = 0; i < 3; i++)
     2371                    active_tabs.push_back(next_tab_id++);
     2372
     2373            // TabItemButton() and Leading/Trailing flags are distinct features which we will demo together.
     2374            // (It is possible to submit regular tabs with Leading/Trailing flags, or TabItemButton tabs without Leading/Trailing flags...
     2375            // but they tend to make more sense together)
     2376            static bool show_leading_button = true;
     2377            static bool show_trailing_button = true;
     2378            ImGui::Checkbox("Show Leading TabItemButton()", &show_leading_button);
     2379            ImGui::Checkbox("Show Trailing TabItemButton()", &show_trailing_button);
     2380
     2381            // Expose some other flags which are useful to showcase how they interact with Leading/Trailing tabs
     2382            static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_FittingPolicyResizeDown;
     2383            ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
     2384            if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
     2385                tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
     2386            if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
     2387                tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
     2388
     2389            if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
     2390            {
     2391                // Demo a Leading TabItemButton(): click the "?" button to open a menu
     2392                if (show_leading_button)
     2393                    if (ImGui::TabItemButton("?", ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_NoTooltip))
     2394                        ImGui::OpenPopup("MyHelpMenu");
     2395                if (ImGui::BeginPopup("MyHelpMenu"))
     2396                {
     2397                    ImGui::Selectable("Hello!");
     2398                    ImGui::EndPopup();
     2399                }
     2400
     2401                // Demo Trailing Tabs: click the "+" button to add a new tab (in your app you may want to use a font icon instead of the "+")
     2402                // Note that we submit it before the regular tabs, but because of the ImGuiTabItemFlags_Trailing flag it will always appear at the end.
     2403                if (show_trailing_button)
     2404                    if (ImGui::TabItemButton("+", ImGuiTabItemFlags_Trailing | ImGuiTabItemFlags_NoTooltip))
     2405                        active_tabs.push_back(next_tab_id++); // Add new tab
     2406
     2407                // Submit our regular tabs
     2408                for (int n = 0; n < active_tabs.Size; )
     2409                {
     2410                    bool open = true;
     2411                    char name[16];
     2412                    snprintf(name, IM_ARRAYSIZE(name), "%04d", active_tabs[n]);
     2413                    if (ImGui::BeginTabItem(name, &open, ImGuiTabItemFlags_None))
     2414                    {
     2415                        ImGui::Text("This is the %s tab!", name);
     2416                        ImGui::EndTabItem();
     2417                    }
     2418
     2419                    if (!open)
     2420                        active_tabs.erase(active_tabs.Data + n);
     2421                    else
     2422                        n++;
     2423                }
     2424
     2425                ImGui::EndTabBar();
     2426            }
     2427            ImGui::Separator();
     2428            ImGui::TreePop();
     2429        }
     2430        ImGui::TreePop();
     2431    }
     2432
     2433    if (ImGui::TreeNode("Groups"))
     2434    {
     2435        HelpMarker(
     2436            "BeginGroup() basically locks the horizontal position for new line. "
     2437            "EndGroup() bundles the whole group so that you can use \"item\" functions such as "
     2438            "IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
     2439        ImGui::BeginGroup();
     2440        {
    12732441            ImGui::BeginGroup();
    12742442            ImGui::Button("AAA");
     
    12842452            ImGui::EndGroup();
    12852453            if (ImGui::IsItemHovered())
    1286                ImGui::SetTooltip("First group hovered");
    1287          }
    1288          // Capture the group size and create widgets using the same size
    1289          ImVec2 size = ImGui::GetItemRectSize();
    1290          const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
    1291          ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
    1292 
    1293          ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y));
    1294          ImGui::SameLine();
    1295          ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x)*0.5f, size.y));
    1296          ImGui::EndGroup();
    1297          ImGui::SameLine();
    1298 
    1299          ImGui::Button("LEVERAGE\nBUZZWORD", size);
    1300          ImGui::SameLine();
    1301 
    1302          if (ImGui::ListBoxHeader("List", size))
    1303          {
     2454                ImGui::SetTooltip("First group hovered");
     2455        }
     2456        // Capture the group size and create widgets using the same size
     2457        ImVec2 size = ImGui::GetItemRectSize();
     2458        const float values[5] = { 0.5f, 0.20f, 0.80f, 0.60f, 0.25f };
     2459        ImGui::PlotHistogram("##values", values, IM_ARRAYSIZE(values), 0, NULL, 0.0f, 1.0f, size);
     2460
     2461        ImGui::Button("ACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
     2462        ImGui::SameLine();
     2463        ImGui::Button("REACTION", ImVec2((size.x - ImGui::GetStyle().ItemSpacing.x) * 0.5f, size.y));
     2464        ImGui::EndGroup();
     2465        ImGui::SameLine();
     2466
     2467        ImGui::Button("LEVERAGE\nBUZZWORD", size);
     2468        ImGui::SameLine();
     2469
     2470        if (ImGui::ListBoxHeader("List", size))
     2471        {
    13042472            ImGui::Selectable("Selected", true);
    13052473            ImGui::Selectable("Not Selected", false);
    13062474            ImGui::ListBoxFooter();
    1307          }
    1308 
    1309          ImGui::TreePop();
    1310       }
    1311 
    1312       if (ImGui::TreeNode("Text Baseline Alignment"))
    1313       {
    1314          ImGui::TextWrapped("(This is testing the vertical alignment that occurs on text to keep it at the same baseline as widgets. Lines only composed of text or \"small\" widgets fit in less vertical spaces than lines with normal widgets)");
    1315 
    1316          ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
    1317          ImGui::Text("Hello\nWorld"); ImGui::SameLine();
    1318          ImGui::Text("Banana");
    1319 
    1320          ImGui::Text("Banana"); ImGui::SameLine();
    1321          ImGui::Text("Hello\nWorld"); ImGui::SameLine();
    1322          ImGui::Text("One\nTwo\nThree");
    1323 
    1324          ImGui::Button("HOP##1"); ImGui::SameLine();
    1325          ImGui::Text("Banana"); ImGui::SameLine();
    1326          ImGui::Text("Hello\nWorld"); ImGui::SameLine();
    1327          ImGui::Text("Banana");
    1328 
    1329          ImGui::Button("HOP##2"); ImGui::SameLine();
    1330          ImGui::Text("Hello\nWorld"); ImGui::SameLine();
    1331          ImGui::Text("Banana");
    1332 
    1333          ImGui::Button("TEST##1"); ImGui::SameLine();
    1334          ImGui::Text("TEST"); ImGui::SameLine();
    1335          ImGui::SmallButton("TEST##2");
    1336 
    1337          ImGui::AlignTextToFramePadding(); // If your line starts with text, call this to align it to upcoming widgets.
    1338          ImGui::Text("Text aligned to Widget"); ImGui::SameLine();
    1339          ImGui::Button("Widget##1"); ImGui::SameLine();
    1340          ImGui::Text("Widget"); ImGui::SameLine();
    1341          ImGui::SmallButton("Widget##2"); ImGui::SameLine();
    1342          ImGui::Button("Widget##3");
    1343 
    1344          // Tree
    1345          const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
    1346          ImGui::Button("Button##1");
    1347          ImGui::SameLine(0.0f, spacing);
    1348          if (ImGui::TreeNode("Node##1")) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); }    // Dummy tree data
    1349 
    1350          ImGui::AlignTextToFramePadding();         // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget. Otherwise you can use SmallButton (smaller fit).
    1351          bool node_open = ImGui::TreeNode("Node##2");  // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add child content.
    1352          ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
    1353          if (node_open) { for (int i = 0; i < 6; i++) ImGui::BulletText("Item %d..", i); ImGui::TreePop(); }   // Dummy tree data
    1354 
    1355                                                                                                                // Bullet
    1356          ImGui::Button("Button##3");
    1357          ImGui::SameLine(0.0f, spacing);
    1358          ImGui::BulletText("Bullet text");
    1359 
    1360          ImGui::AlignTextToFramePadding();
    1361          ImGui::BulletText("Node");
    1362          ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
    1363 
    1364          ImGui::TreePop();
    1365       }
    1366 
    1367       if (ImGui::TreeNode("Scrolling"))
    1368       {
    1369          ImGui::TextWrapped("(Use SetScrollHere() or SetScrollFromPosY() to scroll to a given position.)");
    1370          static bool track = true;
    1371          static int track_line = 50, scroll_to_px = 200;
    1372          ImGui::Checkbox("Track", &track);
    1373          ImGui::PushItemWidth(100);
    1374          ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %.0f");
    1375          bool scroll_to = ImGui::Button("Scroll To Pos");
    1376          ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %.0f px");
    1377          ImGui::PopItemWidth();
    1378          if (scroll_to) track = false;
    1379 
    1380          for (int i = 0; i < 5; i++)
    1381          {
     2475        }
     2476
     2477        ImGui::TreePop();
     2478    }
     2479
     2480    if (ImGui::TreeNode("Text Baseline Alignment"))
     2481    {
     2482        {
     2483            ImGui::BulletText("Text baseline:");
     2484            ImGui::SameLine(); HelpMarker(
     2485                "This is testing the vertical alignment that gets applied on text to keep it aligned with widgets. "
     2486                "Lines only composed of text or \"small\" widgets use less vertical space than lines with framed widgets.");
     2487            ImGui::Indent();
     2488
     2489            ImGui::Text("KO Blahblah"); ImGui::SameLine();
     2490            ImGui::Button("Some framed item"); ImGui::SameLine();
     2491            HelpMarker("Baseline of button will look misaligned with text..");
     2492
     2493            // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
     2494            // (because we don't know what's coming after the Text() statement, we need to move the text baseline
     2495            // down by FramePadding.y ahead of time)
     2496            ImGui::AlignTextToFramePadding();
     2497            ImGui::Text("OK Blahblah"); ImGui::SameLine();
     2498            ImGui::Button("Some framed item"); ImGui::SameLine();
     2499            HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
     2500
     2501            // SmallButton() uses the same vertical padding as Text
     2502            ImGui::Button("TEST##1"); ImGui::SameLine();
     2503            ImGui::Text("TEST"); ImGui::SameLine();
     2504            ImGui::SmallButton("TEST##2");
     2505
     2506            // If your line starts with text, call AlignTextToFramePadding() to align text to upcoming widgets.
     2507            ImGui::AlignTextToFramePadding();
     2508            ImGui::Text("Text aligned to framed item"); ImGui::SameLine();
     2509            ImGui::Button("Item##1"); ImGui::SameLine();
     2510            ImGui::Text("Item"); ImGui::SameLine();
     2511            ImGui::SmallButton("Item##2"); ImGui::SameLine();
     2512            ImGui::Button("Item##3");
     2513
     2514            ImGui::Unindent();
     2515        }
     2516
     2517        ImGui::Spacing();
     2518
     2519        {
     2520            ImGui::BulletText("Multi-line text:");
     2521            ImGui::Indent();
     2522            ImGui::Text("One\nTwo\nThree"); ImGui::SameLine();
     2523            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
     2524            ImGui::Text("Banana");
     2525
     2526            ImGui::Text("Banana"); ImGui::SameLine();
     2527            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
     2528            ImGui::Text("One\nTwo\nThree");
     2529
     2530            ImGui::Button("HOP##1"); ImGui::SameLine();
     2531            ImGui::Text("Banana"); ImGui::SameLine();
     2532            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
     2533            ImGui::Text("Banana");
     2534
     2535            ImGui::Button("HOP##2"); ImGui::SameLine();
     2536            ImGui::Text("Hello\nWorld"); ImGui::SameLine();
     2537            ImGui::Text("Banana");
     2538            ImGui::Unindent();
     2539        }
     2540
     2541        ImGui::Spacing();
     2542
     2543        {
     2544            ImGui::BulletText("Misc items:");
     2545            ImGui::Indent();
     2546
     2547            // SmallButton() sets FramePadding to zero. Text baseline is aligned to match baseline of previous Button.
     2548            ImGui::Button("80x80", ImVec2(80, 80));
     2549            ImGui::SameLine();
     2550            ImGui::Button("50x50", ImVec2(50, 50));
     2551            ImGui::SameLine();
     2552            ImGui::Button("Button()");
     2553            ImGui::SameLine();
     2554            ImGui::SmallButton("SmallButton()");
     2555
     2556            // Tree
     2557            const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
     2558            ImGui::Button("Button##1");
     2559            ImGui::SameLine(0.0f, spacing);
     2560            if (ImGui::TreeNode("Node##1"))
     2561            {
     2562                // Placeholder tree data
     2563                for (int i = 0; i < 6; i++)
     2564                    ImGui::BulletText("Item %d..", i);
     2565                ImGui::TreePop();
     2566            }
     2567
     2568            // Vertically align text node a bit lower so it'll be vertically centered with upcoming widget.
     2569            // Otherwise you can use SmallButton() (smaller fit).
     2570            ImGui::AlignTextToFramePadding();
     2571
     2572            // Common mistake to avoid: if we want to SameLine after TreeNode we need to do it before we add
     2573            // other contents below the node.
     2574            bool node_open = ImGui::TreeNode("Node##2");
     2575            ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##2");
     2576            if (node_open)
     2577            {
     2578                // Placeholder tree data
     2579                for (int i = 0; i < 6; i++)
     2580                    ImGui::BulletText("Item %d..", i);
     2581                ImGui::TreePop();
     2582            }
     2583
     2584            // Bullet
     2585            ImGui::Button("Button##3");
     2586            ImGui::SameLine(0.0f, spacing);
     2587            ImGui::BulletText("Bullet text");
     2588
     2589            ImGui::AlignTextToFramePadding();
     2590            ImGui::BulletText("Node");
     2591            ImGui::SameLine(0.0f, spacing); ImGui::Button("Button##4");
     2592            ImGui::Unindent();
     2593        }
     2594
     2595        ImGui::TreePop();
     2596    }
     2597
     2598    if (ImGui::TreeNode("Scrolling"))
     2599    {
     2600        // Vertical scroll functions
     2601        HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
     2602
     2603        static int track_item = 50;
     2604        static bool enable_track = true;
     2605        static bool enable_extra_decorations = false;
     2606        static float scroll_to_off_px = 0.0f;
     2607        static float scroll_to_pos_px = 200.0f;
     2608
     2609        ImGui::Checkbox("Decoration", &enable_extra_decorations);
     2610
     2611        ImGui::Checkbox("Track", &enable_track);
     2612        ImGui::PushItemWidth(100);
     2613        ImGui::SameLine(140); enable_track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %d");
     2614
     2615        bool scroll_to_off = ImGui::Button("Scroll Offset");
     2616        ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &scroll_to_off_px, 1.00f, 0, FLT_MAX, "+%.0f px");
     2617
     2618        bool scroll_to_pos = ImGui::Button("Scroll To Pos");
     2619        ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, -10, FLT_MAX, "X/Y = %.0f px");
     2620        ImGui::PopItemWidth();
     2621
     2622        if (scroll_to_off || scroll_to_pos)
     2623            enable_track = false;
     2624
     2625        ImGuiStyle& style = ImGui::GetStyle();
     2626        float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
     2627        if (child_w < 1.0f)
     2628            child_w = 1.0f;
     2629        ImGui::PushID("##VerticalScrolling");
     2630        for (int i = 0; i < 5; i++)
     2631        {
    13822632            if (i > 0) ImGui::SameLine();
    13832633            ImGui::BeginGroup();
    1384             ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom");
    1385             ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true);
    1386             if (scroll_to)
    1387                ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f);
    1388             for (int line = 0; line < 100; line++)
    1389             {
    1390                if (track && line == track_line)
    1391                {
    1392                   ImGui::TextColored(ImColor(255, 255, 0), "Line %d", line);
    1393                   ImGui::SetScrollHere(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
    1394                }
    1395                else
    1396                {
    1397                   ImGui::Text("Line %d", line);
    1398                }
    1399             }
    1400             float scroll_y = ImGui::GetScrollY(), scroll_max_y = ImGui::GetScrollMaxY();
     2634            const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
     2635            ImGui::TextUnformatted(names[i]);
     2636
     2637            const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
     2638            const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
     2639            const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), true, child_flags);
     2640            if (ImGui::BeginMenuBar())
     2641            {
     2642                ImGui::TextUnformatted("abc");
     2643                ImGui::EndMenuBar();
     2644            }
     2645            if (scroll_to_off)
     2646                ImGui::SetScrollY(scroll_to_off_px);
     2647            if (scroll_to_pos)
     2648                ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
     2649            if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
     2650            {
     2651                for (int item = 0; item < 100; item++)
     2652                {
     2653                    if (enable_track && item == track_item)
     2654                    {
     2655                        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
     2656                        ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
     2657                    }
     2658                    else
     2659                    {
     2660                        ImGui::Text("Item %d", item);
     2661                    }
     2662                }
     2663            }
     2664            float scroll_y = ImGui::GetScrollY();
     2665            float scroll_max_y = ImGui::GetScrollMaxY();
    14012666            ImGui::EndChild();
    1402             ImGui::Text("%.0f/%0.f", scroll_y, scroll_max_y);
     2667            ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
    14032668            ImGui::EndGroup();
    1404          }
    1405          ImGui::TreePop();
    1406       }
    1407 
    1408       if (ImGui::TreeNode("Horizontal Scrolling"))
    1409       {
    1410          ImGui::Bullet(); ImGui::TextWrapped("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.");
    1411          ImGui::Bullet(); ImGui::TextWrapped("You may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin().");
    1412          static int lines = 7;
    1413          ImGui::SliderInt("Lines", &lines, 1, 15);
    1414          ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
    1415          ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
    1416          ImGui::BeginChild("scrolling", ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30), true, ImGuiWindowFlags_HorizontalScrollbar);
    1417          for (int line = 0; line < lines; line++)
    1418          {
    1419             // Display random stuff (for the sake of this trivial demo we are using basic Button+SameLine. If you want to create your own time line for a real application you may be better off
    1420             // manipulating the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets yourself. You may also want to use the lower-level ImDrawList API)
     2669        }
     2670        ImGui::PopID();
     2671
     2672        // Horizontal scroll functions
     2673        ImGui::Spacing();
     2674        HelpMarker(
     2675            "Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\n"
     2676            "Because the clipping rectangle of most window hides half worth of WindowPadding on the "
     2677            "left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the "
     2678            "equivalent SetScrollFromPosY(+1) wouldn't.");
     2679        ImGui::PushID("##HorizontalScrolling");
     2680        for (int i = 0; i < 5; i++)
     2681        {
     2682            float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
     2683            ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
     2684            ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
     2685            bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), true, child_flags);
     2686            if (scroll_to_off)
     2687                ImGui::SetScrollX(scroll_to_off_px);
     2688            if (scroll_to_pos)
     2689                ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
     2690            if (child_is_visible) // Avoid calling SetScrollHereY when running with culled items
     2691            {
     2692                for (int item = 0; item < 100; item++)
     2693                {
     2694                    if (enable_track && item == track_item)
     2695                    {
     2696                        ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
     2697                        ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
     2698                    }
     2699                    else
     2700                    {
     2701                        ImGui::Text("Item %d", item);
     2702                    }
     2703                    ImGui::SameLine();
     2704                }
     2705            }
     2706            float scroll_x = ImGui::GetScrollX();
     2707            float scroll_max_x = ImGui::GetScrollMaxX();
     2708            ImGui::EndChild();
     2709            ImGui::SameLine();
     2710            const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
     2711            ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
     2712            ImGui::Spacing();
     2713        }
     2714        ImGui::PopID();
     2715
     2716        // Miscellaneous Horizontal Scrolling Demo
     2717        HelpMarker(
     2718            "Horizontal scrolling for a window is enabled via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\n"
     2719            "You may want to also explicitly specify content width by using SetNextWindowContentWidth() before Begin().");
     2720        static int lines = 7;
     2721        ImGui::SliderInt("Lines", &lines, 1, 15);
     2722        ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
     2723        ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
     2724        ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
     2725        ImGui::BeginChild("scrolling", scrolling_child_size, true, ImGuiWindowFlags_HorizontalScrollbar);
     2726        for (int line = 0; line < lines; line++)
     2727        {
     2728            // Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
     2729            // If you want to create your own time line for a real application you may be better off manipulating
     2730            // the cursor position yourself, aka using SetCursorPos/SetCursorScreenPos to position the widgets
     2731            // yourself. You may also want to use the lower-level ImDrawList API.
    14212732            int num_buttons = 10 + ((line & 1) ? line * 9 : line * 3);
    14222733            for (int n = 0; n < num_buttons; n++)
    14232734            {
    1424                if (n > 0) ImGui::SameLine();
    1425                ImGui::PushID(n + line * 1000);
    1426                char num_buf[16];
    1427                sprintf(num_buf, "%d", n);
    1428                const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
    1429                float hue = n * 0.05f;
    1430                ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
    1431                ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
    1432                ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
    1433                ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
    1434                ImGui::PopStyleColor(3);
    1435                ImGui::PopID();
    1436             }
    1437          }
    1438          float scroll_x = ImGui::GetScrollX(), scroll_max_x = ImGui::GetScrollMaxX();
    1439          ImGui::EndChild();
    1440          ImGui::PopStyleVar(2);
    1441          float scroll_x_delta = 0.0f;
    1442          ImGui::SmallButton("<<"); if (ImGui::IsItemActive()) scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine();
    1443          ImGui::Text("Scroll from code"); ImGui::SameLine();
    1444          ImGui::SmallButton(">>"); if (ImGui::IsItemActive()) scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f; ImGui::SameLine();
    1445          ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
    1446          if (scroll_x_delta != 0.0f)
    1447          {
    1448             ImGui::BeginChild("scrolling"); // Demonstrate a trick: you can use Begin to set yourself in the context of another window (here we are already out of your child window)
     2735                if (n > 0) ImGui::SameLine();
     2736                ImGui::PushID(n + line * 1000);
     2737                char num_buf[16];
     2738                sprintf(num_buf, "%d", n);
     2739                const char* label = (!(n % 15)) ? "FizzBuzz" : (!(n % 3)) ? "Fizz" : (!(n % 5)) ? "Buzz" : num_buf;
     2740                float hue = n * 0.05f;
     2741                ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(hue, 0.6f, 0.6f));
     2742                ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(hue, 0.7f, 0.7f));
     2743                ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(hue, 0.8f, 0.8f));
     2744                ImGui::Button(label, ImVec2(40.0f + sinf((float)(line + n)) * 20.0f, 0.0f));
     2745                ImGui::PopStyleColor(3);
     2746                ImGui::PopID();
     2747            }
     2748        }
     2749        float scroll_x = ImGui::GetScrollX();
     2750        float scroll_max_x = ImGui::GetScrollMaxX();
     2751        ImGui::EndChild();
     2752        ImGui::PopStyleVar(2);
     2753        float scroll_x_delta = 0.0f;
     2754        ImGui::SmallButton("<<");
     2755        if (ImGui::IsItemActive())
     2756            scroll_x_delta = -ImGui::GetIO().DeltaTime * 1000.0f;
     2757        ImGui::SameLine();
     2758        ImGui::Text("Scroll from code"); ImGui::SameLine();
     2759        ImGui::SmallButton(">>");
     2760        if (ImGui::IsItemActive())
     2761            scroll_x_delta = +ImGui::GetIO().DeltaTime * 1000.0f;
     2762        ImGui::SameLine();
     2763        ImGui::Text("%.0f/%.0f", scroll_x, scroll_max_x);
     2764        if (scroll_x_delta != 0.0f)
     2765        {
     2766            // Demonstrate a trick: you can use Begin to set yourself in the context of another window
     2767            // (here we are already out of your child window)
     2768            ImGui::BeginChild("scrolling");
    14492769            ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
     2770            ImGui::EndChild();
     2771        }
     2772        ImGui::Spacing();
     2773
     2774        static bool show_horizontal_contents_size_demo_window = false;
     2775        ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
     2776
     2777        if (show_horizontal_contents_size_demo_window)
     2778        {
     2779            static bool show_h_scrollbar = true;
     2780            static bool show_button = true;
     2781            static bool show_tree_nodes = true;
     2782            static bool show_text_wrapped = false;
     2783            static bool show_columns = true;
     2784            static bool show_tab_bar = true;
     2785            static bool show_child = false;
     2786            static bool explicit_content_size = false;
     2787            static float contents_size_x = 300.0f;
     2788            if (explicit_content_size)
     2789                ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
     2790            ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
     2791            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
     2792            ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
     2793            HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
     2794            ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
     2795            ImGui::Checkbox("Button", &show_button);            // Will grow contents size (unless explicitly overwritten)
     2796            ImGui::Checkbox("Tree nodes", &show_tree_nodes);    // Will grow contents size and display highlight over full width
     2797            ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
     2798            ImGui::Checkbox("Columns", &show_columns);          // Will use contents size
     2799            ImGui::Checkbox("Tab bar", &show_tab_bar);          // Will use contents size
     2800            ImGui::Checkbox("Child", &show_child);              // Will grow and use contents size
     2801            ImGui::Checkbox("Explicit content size", &explicit_content_size);
     2802            ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
     2803            if (explicit_content_size)
     2804            {
     2805                ImGui::SameLine();
     2806                ImGui::SetNextItemWidth(100);
     2807                ImGui::DragFloat("##csx", &contents_size_x);
     2808                ImVec2 p = ImGui::GetCursorScreenPos();
     2809                ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
     2810                ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
     2811                ImGui::Dummy(ImVec2(0, 10));
     2812            }
     2813            ImGui::PopStyleVar(2);
     2814            ImGui::Separator();
     2815            if (show_button)
     2816            {
     2817                ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
     2818            }
     2819            if (show_tree_nodes)
     2820            {
     2821                bool open = true;
     2822                if (ImGui::TreeNode("this is a tree node"))
     2823                {
     2824                    if (ImGui::TreeNode("another one of those tree node..."))
     2825                    {
     2826                        ImGui::Text("Some tree contents");
     2827                        ImGui::TreePop();
     2828                    }
     2829                    ImGui::TreePop();
     2830                }
     2831                ImGui::CollapsingHeader("CollapsingHeader", &open);
     2832            }
     2833            if (show_text_wrapped)
     2834            {
     2835                ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
     2836            }
     2837            if (show_columns)
     2838            {
     2839                ImGui::Columns(4);
     2840                for (int n = 0; n < 4; n++)
     2841                {
     2842                    ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
     2843                    ImGui::NextColumn();
     2844                }
     2845                ImGui::Columns(1);
     2846            }
     2847            if (show_tab_bar && ImGui::BeginTabBar("Hello"))
     2848            {
     2849                if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
     2850                if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
     2851                if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
     2852                if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
     2853                ImGui::EndTabBar();
     2854            }
     2855            if (show_child)
     2856            {
     2857                ImGui::BeginChild("child", ImVec2(0, 0), true);
     2858                ImGui::EndChild();
     2859            }
    14502860            ImGui::End();
    1451          }
    1452          ImGui::TreePop();
    1453       }
    1454 
    1455       if (ImGui::TreeNode("Clipping"))
    1456       {
    1457          static ImVec2 size(100, 100), offset(50, 20);
    1458          ImGui::TextWrapped("On a per-widget basis we are occasionally clipping text CPU-side if it won't fit in its frame. Otherwise we are doing coarser clipping + passing a scissor rectangle to the renderer. The system is designed to try minimizing both execution and CPU/GPU rendering cost.");
    1459          ImGui::DragFloat2("size", (float*)&size, 0.5f, 0.0f, 200.0f, "%.0f");
    1460          ImGui::TextWrapped("(Click and drag)");
    1461          ImVec2 pos = ImGui::GetCursorScreenPos();
    1462          ImVec4 clip_rect(pos.x, pos.y, pos.x + size.x, pos.y + size.y);
    1463          ImGui::InvisibleButton("##dummy", size);
    1464          if (ImGui::IsItemActive() && ImGui::IsMouseDragging()) { offset.x += ImGui::GetIO().MouseDelta.x; offset.y += ImGui::GetIO().MouseDelta.y; }
    1465          ImGui::GetWindowDrawList()->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(90, 90, 120, 255));
    1466          ImGui::GetWindowDrawList()->AddText(ImGui::GetFont(), ImGui::GetFontSize()*2.0f, ImVec2(pos.x + offset.x, pos.y + offset.y), IM_COL32(255, 255, 255, 255), "Line 1 hello\nLine 2 clip me!", NULL, 0.0f, &clip_rect);
    1467          ImGui::TreePop();
    1468       }
    1469    }
    1470 
    1471    if (ImGui::CollapsingHeader("Popups & Modal windows"))
    1472    {
    1473       if (ImGui::TreeNode("Popups"))
    1474       {
    1475          ImGui::TextWrapped("When a popup is active, it inhibits interacting with windows that are behind the popup. Clicking outside the popup closes it.");
    1476 
    1477          static int selected_fish = -1;
    1478          const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
    1479          static bool toggles[] = { true, false, false, false, false };
    1480 
    1481          // Simple selection popup
    1482          // (If you want to show the current selection inside the Button itself, you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
    1483          if (ImGui::Button("Select.."))
    1484             ImGui::OpenPopup("select");
    1485          ImGui::SameLine();
    1486          ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
    1487          if (ImGui::BeginPopup("select"))
    1488          {
     2861        }
     2862
     2863        ImGui::TreePop();
     2864    }
     2865
     2866    if (ImGui::TreeNode("Clipping"))
     2867    {
     2868        static ImVec2 size(100.0f, 100.0f);
     2869        static ImVec2 offset(30.0f, 30.0f);
     2870        ImGui::DragFloat2("size", (float*)&size, 0.5f, 1.0f, 200.0f, "%.0f");
     2871        ImGui::TextWrapped("(Click and drag to scroll)");
     2872
     2873        for (int n = 0; n < 3; n++)
     2874        {
     2875            if (n > 0)
     2876                ImGui::SameLine();
     2877            ImGui::PushID(n);
     2878            ImGui::BeginGroup(); // Lock X position
     2879
     2880            ImGui::InvisibleButton("##empty", size);
     2881            if (ImGui::IsItemActive() && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
     2882            {
     2883                offset.x += ImGui::GetIO().MouseDelta.x;
     2884                offset.y += ImGui::GetIO().MouseDelta.y;
     2885            }
     2886            const ImVec2 p0 = ImGui::GetItemRectMin();
     2887            const ImVec2 p1 = ImGui::GetItemRectMax();
     2888            const char* text_str = "Line 1 hello\nLine 2 clip me!";
     2889            const ImVec2 text_pos = ImVec2(p0.x + offset.x, p0.y + offset.y);
     2890            ImDrawList* draw_list = ImGui::GetWindowDrawList();
     2891
     2892            switch (n)
     2893            {
     2894            case 0:
     2895                HelpMarker(
     2896                    "Using ImGui::PushClipRect():\n"
     2897                    "Will alter ImGui hit-testing logic + ImDrawList rendering.\n"
     2898                    "(use this if you want your clipping rectangle to affect interactions)");
     2899                ImGui::PushClipRect(p0, p1, true);
     2900                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
     2901                draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
     2902                ImGui::PopClipRect();
     2903                break;
     2904            case 1:
     2905                HelpMarker(
     2906                    "Using ImDrawList::PushClipRect():\n"
     2907                    "Will alter ImDrawList rendering only.\n"
     2908                    "(use this as a shortcut if you are only using ImDrawList calls)");
     2909                draw_list->PushClipRect(p0, p1, true);
     2910                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
     2911                draw_list->AddText(text_pos, IM_COL32_WHITE, text_str);
     2912                draw_list->PopClipRect();
     2913                break;
     2914            case 2:
     2915                HelpMarker(
     2916                    "Using ImDrawList::AddText() with a fine ClipRect:\n"
     2917                    "Will alter only this specific ImDrawList::AddText() rendering.\n"
     2918                    "(this is often used internally to avoid altering the clipping rectangle and minimize draw calls)");
     2919                ImVec4 clip_rect(p0.x, p0.y, p1.x, p1.y); // AddText() takes a ImVec4* here so let's convert.
     2920                draw_list->AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255));
     2921                draw_list->AddText(ImGui::GetFont(), ImGui::GetFontSize(), text_pos, IM_COL32_WHITE, text_str, NULL, 0.0f, &clip_rect);
     2922                break;
     2923            }
     2924            ImGui::EndGroup();
     2925            ImGui::PopID();
     2926        }
     2927
     2928        ImGui::TreePop();
     2929    }
     2930}
     2931
     2932static void ShowDemoWindowPopups()
     2933{
     2934    if (!ImGui::CollapsingHeader("Popups & Modal windows"))
     2935        return;
     2936
     2937    // The properties of popups windows are:
     2938    // - They block normal mouse hovering detection outside them. (*)
     2939    // - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
     2940    // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as
     2941    //   we are used to with regular Begin() calls. User can manipulate the visibility state by calling OpenPopup().
     2942    // (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even
     2943    //     when normally blocked by a popup.
     2944    // Those three properties are connected. The library needs to hold their visibility state BECAUSE it can close
     2945    // popups at any time.
     2946
     2947    // Typical use for regular windows:
     2948    //   bool my_tool_is_active = false; if (ImGui::Button("Open")) my_tool_is_active = true; [...] if (my_tool_is_active) Begin("My Tool", &my_tool_is_active) { [...] } End();
     2949    // Typical use for popups:
     2950    //   if (ImGui::Button("Open")) ImGui::OpenPopup("MyPopup"); if (ImGui::BeginPopup("MyPopup") { [...] EndPopup(); }
     2951
     2952    // With popups we have to go through a library call (here OpenPopup) to manipulate the visibility state.
     2953    // This may be a bit confusing at first but it should quickly make sense. Follow on the examples below.
     2954
     2955    if (ImGui::TreeNode("Popups"))
     2956    {
     2957        ImGui::TextWrapped(
     2958            "When a popup is active, it inhibits interacting with windows that are behind the popup. "
     2959            "Clicking outside the popup closes it.");
     2960
     2961        static int selected_fish = -1;
     2962        const char* names[] = { "Bream", "Haddock", "Mackerel", "Pollock", "Tilefish" };
     2963        static bool toggles[] = { true, false, false, false, false };
     2964
     2965        // Simple selection popup (if you want to show the current selection inside the Button itself,
     2966        // you may want to build a string using the "###" operator to preserve a constant ID with a variable label)
     2967        if (ImGui::Button("Select.."))
     2968            ImGui::OpenPopup("my_select_popup");
     2969        ImGui::SameLine();
     2970        ImGui::TextUnformatted(selected_fish == -1 ? "<None>" : names[selected_fish]);
     2971        if (ImGui::BeginPopup("my_select_popup"))
     2972        {
    14892973            ImGui::Text("Aquarium");
    14902974            ImGui::Separator();
    14912975            for (int i = 0; i < IM_ARRAYSIZE(names); i++)
    1492                if (ImGui::Selectable(names[i]))
    1493                   selected_fish = i;
     2976                if (ImGui::Selectable(names[i]))
     2977                    selected_fish = i;
    14942978            ImGui::EndPopup();
    1495          }
    1496 
    1497          // Showing a menu with toggles
    1498          if (ImGui::Button("Toggle.."))
    1499             ImGui::OpenPopup("toggle");
    1500          if (ImGui::BeginPopup("toggle"))
    1501          {
     2979        }
     2980
     2981        // Showing a menu with toggles
     2982        if (ImGui::Button("Toggle.."))
     2983            ImGui::OpenPopup("my_toggle_popup");
     2984        if (ImGui::BeginPopup("my_toggle_popup"))
     2985        {
    15022986            for (int i = 0; i < IM_ARRAYSIZE(names); i++)
    1503                ImGui::MenuItem(names[i], "", &toggles[i]);
     2987                ImGui::MenuItem(names[i], "", &toggles[i]);
    15042988            if (ImGui::BeginMenu("Sub-menu"))
    15052989            {
    1506                ImGui::MenuItem("Click me");
    1507                ImGui::EndMenu();
     2990                ImGui::MenuItem("Click me");
     2991                ImGui::EndMenu();
    15082992            }
    15092993
     
    15112995            ImGui::Text("Tooltip here");
    15122996            if (ImGui::IsItemHovered())
    1513                ImGui::SetTooltip("I am a tooltip over a popup");
     2997                ImGui::SetTooltip("I am a tooltip over a popup");
    15142998
    15152999            if (ImGui::Button("Stacked Popup"))
    1516                ImGui::OpenPopup("another popup");
     3000                ImGui::OpenPopup("another popup");
    15173001            if (ImGui::BeginPopup("another popup"))
    15183002            {
    1519                for (int i = 0; i < IM_ARRAYSIZE(names); i++)
    1520                   ImGui::MenuItem(names[i], "", &toggles[i]);
    1521                if (ImGui::BeginMenu("Sub-menu"))
    1522                {
    1523                   ImGui::MenuItem("Click me");
    1524                   ImGui::EndMenu();
    1525                }
    1526                ImGui::EndPopup();
     3003                for (int i = 0; i < IM_ARRAYSIZE(names); i++)
     3004                    ImGui::MenuItem(names[i], "", &toggles[i]);
     3005                if (ImGui::BeginMenu("Sub-menu"))
     3006                {
     3007                    ImGui::MenuItem("Click me");
     3008                    if (ImGui::Button("Stacked Popup"))
     3009                        ImGui::OpenPopup("another popup");
     3010                    if (ImGui::BeginPopup("another popup"))
     3011                    {
     3012                        ImGui::Text("I am the last one here.");
     3013                        ImGui::EndPopup();
     3014                    }
     3015                    ImGui::EndMenu();
     3016                }
     3017                ImGui::EndPopup();
    15273018            }
    15283019            ImGui::EndPopup();
    1529          }
    1530 
    1531          if (ImGui::Button("Popup Menu.."))
    1532             ImGui::OpenPopup("FilePopup");
    1533          if (ImGui::BeginPopup("FilePopup"))
    1534          {
     3020        }
     3021
     3022        // Call the more complete ShowExampleMenuFile which we use in various places of this demo
     3023        if (ImGui::Button("File Menu.."))
     3024            ImGui::OpenPopup("my_file_popup");
     3025        if (ImGui::BeginPopup("my_file_popup"))
     3026        {
    15353027            ShowExampleMenuFile();
    15363028            ImGui::EndPopup();
    1537          }
    1538 
    1539          ImGui::TreePop();
    1540       }
    1541 
    1542       if (ImGui::TreeNode("Context menus"))
    1543       {
    1544          // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
    1545          //    if (IsItemHovered() && IsMouseClicked(0))
    1546          //       OpenPopup(id);
    1547          //    return BeginPopup(id);
    1548          // For more advanced uses you may want to replicate and cuztomize this code. This the comments inside BeginPopupContextItem() implementation.
    1549          static float value = 0.5f;
    1550          ImGui::Text("Value = %.3f (<-- right-click here)", value);
    1551          if (ImGui::BeginPopupContextItem("item context menu"))
    1552          {
     3029        }
     3030
     3031        ImGui::TreePop();
     3032    }
     3033
     3034    if (ImGui::TreeNode("Context menus"))
     3035    {
     3036        // BeginPopupContextItem() is a helper to provide common/simple popup behavior of essentially doing:
     3037        //    if (IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right))
     3038        //       OpenPopup(id);
     3039        //    return BeginPopup(id);
     3040        // For more advanced uses you may want to replicate and customize this code.
     3041        // See details in BeginPopupContextItem().
     3042        static float value = 0.5f;
     3043        ImGui::Text("Value = %.3f (<-- right-click here)", value);
     3044        if (ImGui::BeginPopupContextItem("item context menu"))
     3045        {
    15533046            if (ImGui::Selectable("Set to zero")) value = 0.0f;
    15543047            if (ImGui::Selectable("Set to PI")) value = 3.1415f;
    1555             ImGui::PushItemWidth(-1);
     3048            ImGui::SetNextItemWidth(-1);
    15563049            ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f);
    1557             ImGui::PopItemWidth();
    15583050            ImGui::EndPopup();
    1559          }
    1560 
    1561          static char name[32] = "Label1";
    1562          char buf[64]; sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
    1563          ImGui::Button(buf);
    1564          if (ImGui::BeginPopupContextItem()) // When used after an item that has an ID (here the Button), we can skip providing an ID to BeginPopupContextItem().
    1565          {
     3051        }
     3052
     3053        // We can also use OpenPopupOnItemClick() which is the same as BeginPopupContextItem() but without the
     3054        // Begin() call. So here we will make it that clicking on the text field with the right mouse button (1)
     3055        // will toggle the visibility of the popup above.
     3056        ImGui::Text("(You can also right-click me to open the same popup as above.)");
     3057        ImGui::OpenPopupOnItemClick("item context menu", 1);
     3058
     3059        // When used after an item that has an ID (e.g.Button), we can skip providing an ID to BeginPopupContextItem().
     3060        // BeginPopupContextItem() will use the last item ID as the popup ID.
     3061        // In addition here, we want to include your editable label inside the button label.
     3062        // We use the ### operator to override the ID (read FAQ about ID for details)
     3063        static char name[32] = "Label1";
     3064        char buf[64];
     3065        sprintf(buf, "Button: %s###Button", name); // ### operator override ID ignoring the preceding label
     3066        ImGui::Button(buf);
     3067        if (ImGui::BeginPopupContextItem())
     3068        {
    15663069            ImGui::Text("Edit name:");
    15673070            ImGui::InputText("##edit", name, IM_ARRAYSIZE(name));
    15683071            if (ImGui::Button("Close"))
    1569                ImGui::CloseCurrentPopup();
     3072                ImGui::CloseCurrentPopup();
    15703073            ImGui::EndPopup();
    1571          }
    1572          ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
    1573 
    1574          ImGui::TreePop();
    1575       }
    1576 
    1577       if (ImGui::TreeNode("Modals"))
    1578       {
    1579          ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside the window.");
    1580 
    1581          if (ImGui::Button("Delete.."))
     3074        }
     3075        ImGui::SameLine(); ImGui::Text("(<-- right-click here)");
     3076
     3077        ImGui::TreePop();
     3078    }
     3079
     3080    if (ImGui::TreeNode("Modals"))
     3081    {
     3082        ImGui::TextWrapped("Modal windows are like popups but the user cannot close them by clicking outside.");
     3083
     3084        if (ImGui::Button("Delete.."))
    15823085            ImGui::OpenPopup("Delete?");
    1583          if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
    1584          {
     3086
     3087        // Always center this window when appearing
     3088        ImVec2 center(ImGui::GetIO().DisplaySize.x * 0.5f, ImGui::GetIO().DisplaySize.y * 0.5f);
     3089        ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
     3090
     3091        if (ImGui::BeginPopupModal("Delete?", NULL, ImGuiWindowFlags_AlwaysAutoResize))
     3092        {
    15853093            ImGui::Text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
    15863094            ImGui::Separator();
    15873095
    1588             //static int dummy_i = 0;
    1589             //ImGui::Combo("Combo", &dummy_i, "Delete\0Delete harder\0");
     3096            //static int unused_i = 0;
     3097            //ImGui::Combo("Combo", &unused_i, "Delete\0Delete harder\0");
    15903098
    15913099            static bool dont_ask_me_next_time = false;
     
    15993107            if (ImGui::Button("Cancel", ImVec2(120, 0))) { ImGui::CloseCurrentPopup(); }
    16003108            ImGui::EndPopup();
    1601          }
    1602 
    1603          if (ImGui::Button("Stacked modals.."))
     3109        }
     3110
     3111        if (ImGui::Button("Stacked modals.."))
    16043112            ImGui::OpenPopup("Stacked 1");
    1605          if (ImGui::BeginPopupModal("Stacked 1"))
    1606          {
    1607             ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDarkening] for darkening.");
     3113        if (ImGui::BeginPopupModal("Stacked 1", NULL, ImGuiWindowFlags_MenuBar))
     3114        {
     3115            if (ImGui::BeginMenuBar())
     3116            {
     3117                if (ImGui::BeginMenu("File"))
     3118                {
     3119                    if (ImGui::MenuItem("Some menu item")) {}
     3120                    ImGui::EndMenu();
     3121                }
     3122                ImGui::EndMenuBar();
     3123            }
     3124            ImGui::Text("Hello from Stacked The First\nUsing style.Colors[ImGuiCol_ModalWindowDimBg] behind it.");
     3125
     3126            // Testing behavior of widgets stacking their own regular popups over the modal.
    16083127            static int item = 1;
     3128            static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
    16093129            ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
    1610             static float color[4] = { 0.4f,0.7f,0.0f,0.5f };
    1611             ImGui::ColorEdit4("color", color);  // This is to test behavior of stacked regular popups over a modal
     3130            ImGui::ColorEdit4("color", color);
    16123131
    16133132            if (ImGui::Button("Add another modal.."))
    1614                ImGui::OpenPopup("Stacked 2");
    1615             if (ImGui::BeginPopupModal("Stacked 2"))
    1616             {
    1617                ImGui::Text("Hello from Stacked The Second!");
    1618                if (ImGui::Button("Close"))
    1619                   ImGui::CloseCurrentPopup();
    1620                ImGui::EndPopup();
     3133                ImGui::OpenPopup("Stacked 2");
     3134
     3135            // Also demonstrate passing a bool* to BeginPopupModal(), this will create a regular close button which
     3136            // will close the popup. Note that the visibility state of popups is owned by imgui, so the input value
     3137            // of the bool actually doesn't matter here.
     3138            bool unused_open = true;
     3139            if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
     3140            {
     3141                ImGui::Text("Hello from Stacked The Second!");
     3142                if (ImGui::Button("Close"))
     3143                    ImGui::CloseCurrentPopup();
     3144                ImGui::EndPopup();
    16213145            }
    16223146
    16233147            if (ImGui::Button("Close"))
    1624                ImGui::CloseCurrentPopup();
     3148                ImGui::CloseCurrentPopup();
    16253149            ImGui::EndPopup();
    1626          }
    1627 
    1628          ImGui::TreePop();
    1629       }
    1630 
    1631       if (ImGui::TreeNode("Menus inside a regular window"))
    1632       {
    1633          ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
    1634          ImGui::Separator();
    1635          // NB: As a quirk in this very specific example, we want to differentiate the parent of this menu from the parent of the various popup menus above.
    1636          // To do so we are encloding the items in a PushID()/PopID() block to make them two different menusets. If we don't, opening any popup above and hovering our menu here
    1637          // would open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it, which is the desired behavior for regular menus.
    1638          ImGui::PushID("foo");
    1639          ImGui::MenuItem("Menu item", "CTRL+M");
    1640          if (ImGui::BeginMenu("Menu inside a regular window"))
    1641          {
     3150        }
     3151
     3152        ImGui::TreePop();
     3153    }
     3154
     3155    if (ImGui::TreeNode("Menus inside a regular window"))
     3156    {
     3157        ImGui::TextWrapped("Below we are testing adding menu items to a regular window. It's rather unusual but should work!");
     3158        ImGui::Separator();
     3159
     3160        // Note: As a quirk in this very specific example, we want to differentiate the parent of this menu from the
     3161        // parent of the various popup menus above. To do so we are encloding the items in a PushID()/PopID() block
     3162        // to make them two different menusets. If we don't, opening any popup above and hovering our menu here would
     3163        // open it. This is because once a menu is active, we allow to switch to a sibling menu by just hovering on it,
     3164        // which is the desired behavior for regular menus.
     3165        ImGui::PushID("foo");
     3166        ImGui::MenuItem("Menu item", "CTRL+M");
     3167        if (ImGui::BeginMenu("Menu inside a regular window"))
     3168        {
    16423169            ShowExampleMenuFile();
    16433170            ImGui::EndMenu();
    1644          }
    1645          ImGui::PopID();
    1646          ImGui::Separator();
    1647          ImGui::TreePop();
    1648       }
    1649    }
    1650 
    1651    if (ImGui::CollapsingHeader("Columns"))
    1652    {
    1653       ImGui::PushID("Columns");
    1654 
    1655       // Basic columns
    1656       if (ImGui::TreeNode("Basic"))
    1657       {
    1658          ImGui::Text("Without border:");
    1659          ImGui::Columns(3, "mycolumns3", false);  // 3-ways, no border
    1660          ImGui::Separator();
    1661          for (int n = 0; n < 14; n++)
    1662          {
     3171        }
     3172        ImGui::PopID();
     3173        ImGui::Separator();
     3174        ImGui::TreePop();
     3175    }
     3176}
     3177
     3178static void ShowDemoWindowColumns()
     3179{
     3180    if (!ImGui::CollapsingHeader("Columns"))
     3181        return;
     3182
     3183    ImGui::PushID("Columns");
     3184
     3185    static bool disable_indent = false;
     3186    ImGui::Checkbox("Disable tree indentation", &disable_indent);
     3187    ImGui::SameLine();
     3188    HelpMarker("Disable the indenting of tree nodes so demo columns can use the full window width.");
     3189    if (disable_indent)
     3190        ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
     3191
     3192    // Basic columns
     3193    if (ImGui::TreeNode("Basic"))
     3194    {
     3195        ImGui::Text("Without border:");
     3196        ImGui::Columns(3, "mycolumns3", false);  // 3-ways, no border
     3197        ImGui::Separator();
     3198        for (int n = 0; n < 14; n++)
     3199        {
    16633200            char label[32];
    16643201            sprintf(label, "Item %d", n);
    16653202            if (ImGui::Selectable(label)) {}
    1666             //if (ImGui::Button(label, ImVec2(-1,0))) {}
     3203            //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
    16673204            ImGui::NextColumn();
    1668          }
    1669          ImGui::Columns(1);
    1670          ImGui::Separator();
    1671 
    1672          ImGui::Text("With border:");
    1673          ImGui::Columns(4, "mycolumns"); // 4-ways, with border
    1674          ImGui::Separator();
    1675          ImGui::Text("ID"); ImGui::NextColumn();
    1676          ImGui::Text("Name"); ImGui::NextColumn();
    1677          ImGui::Text("Path"); ImGui::NextColumn();
    1678          ImGui::Text("Hovered"); ImGui::NextColumn();
    1679          ImGui::Separator();
    1680          const char* names[3] = { "One", "Two", "Three" };
    1681          const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
    1682          static int selected = -1;
    1683          for (int i = 0; i < 3; i++)
    1684          {
     3205        }
     3206        ImGui::Columns(1);
     3207        ImGui::Separator();
     3208
     3209        ImGui::Text("With border:");
     3210        ImGui::Columns(4, "mycolumns"); // 4-ways, with border
     3211        ImGui::Separator();
     3212        ImGui::Text("ID"); ImGui::NextColumn();
     3213        ImGui::Text("Name"); ImGui::NextColumn();
     3214        ImGui::Text("Path"); ImGui::NextColumn();
     3215        ImGui::Text("Hovered"); ImGui::NextColumn();
     3216        ImGui::Separator();
     3217        const char* names[3] = { "One", "Two", "Three" };
     3218        const char* paths[3] = { "/path/one", "/path/two", "/path/three" };
     3219        static int selected = -1;
     3220        for (int i = 0; i < 3; i++)
     3221        {
    16853222            char label[32];
    16863223            sprintf(label, "%04d", i);
    16873224            if (ImGui::Selectable(label, selected == i, ImGuiSelectableFlags_SpanAllColumns))
    1688                selected = i;
     3225                selected = i;
    16893226            bool hovered = ImGui::IsItemHovered();
    16903227            ImGui::NextColumn();
     
    16923229            ImGui::Text(paths[i]); ImGui::NextColumn();
    16933230            ImGui::Text("%d", hovered); ImGui::NextColumn();
    1694          }
    1695          ImGui::Columns(1);
    1696          ImGui::Separator();
    1697          ImGui::TreePop();
    1698       }
    1699 
    1700       // Create multiple items in a same cell before switching to next column
    1701       if (ImGui::TreeNode("Mixed items"))
    1702       {
    1703          ImGui::Columns(3, "mixed");
    1704          ImGui::Separator();
    1705 
    1706          ImGui::Text("Hello");
    1707          ImGui::Button("Banana");
    1708          ImGui::NextColumn();
    1709 
    1710          ImGui::Text("ImGui");
    1711          ImGui::Button("Apple");
    1712          static float foo = 1.0f;
    1713          ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
    1714          ImGui::Text("An extra line here.");
    1715          ImGui::NextColumn();
    1716 
    1717          ImGui::Text("Sailor");
    1718          ImGui::Button("Corniflower");
    1719          static float bar = 1.0f;
    1720          ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
    1721          ImGui::NextColumn();
    1722 
    1723          if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
    1724          if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
    1725          if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
    1726          ImGui::Columns(1);
    1727          ImGui::Separator();
    1728          ImGui::TreePop();
    1729       }
    1730 
    1731       // Word wrapping
    1732       if (ImGui::TreeNode("Word-wrapping"))
    1733       {
    1734          ImGui::Columns(2, "word-wrapping");
    1735          ImGui::Separator();
    1736          ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
    1737          ImGui::TextWrapped("Hello Left");
    1738          ImGui::NextColumn();
    1739          ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
    1740          ImGui::TextWrapped("Hello Right");
    1741          ImGui::Columns(1);
    1742          ImGui::Separator();
    1743          ImGui::TreePop();
    1744       }
    1745 
    1746       if (ImGui::TreeNode("Borders"))
    1747       {
    1748          // NB: Future columns API should allow automatic horizontal borders.
    1749          static bool h_borders = true;
    1750          static bool v_borders = true;
    1751          ImGui::Checkbox("horizontal", &h_borders);
    1752          ImGui::SameLine();
    1753          ImGui::Checkbox("vertical", &v_borders);
    1754          ImGui::Columns(4, NULL, v_borders);
    1755          for (int i = 0; i < 4 * 3; i++)
    1756          {
     3231        }
     3232        ImGui::Columns(1);
     3233        ImGui::Separator();
     3234        ImGui::TreePop();
     3235    }
     3236
     3237    if (ImGui::TreeNode("Borders"))
     3238    {
     3239        // NB: Future columns API should allow automatic horizontal borders.
     3240        static bool h_borders = true;
     3241        static bool v_borders = true;
     3242        static int columns_count = 4;
     3243        const int lines_count = 3;
     3244        ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
     3245        ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
     3246        if (columns_count < 2)
     3247            columns_count = 2;
     3248        ImGui::SameLine();
     3249        ImGui::Checkbox("horizontal", &h_borders);
     3250        ImGui::SameLine();
     3251        ImGui::Checkbox("vertical", &v_borders);
     3252        ImGui::Columns(columns_count, NULL, v_borders);
     3253        for (int i = 0; i < columns_count * lines_count; i++)
     3254        {
    17573255            if (h_borders && ImGui::GetColumnIndex() == 0)
    1758                ImGui::Separator();
     3256                ImGui::Separator();
    17593257            ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
    1760             ImGui::Text("Width %.2f\nOffset %.2f", ImGui::GetColumnWidth(), ImGui::GetColumnOffset());
     3258            ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
     3259            ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
     3260            ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
     3261            ImGui::Text("Long text that is likely to clip");
     3262            ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
    17613263            ImGui::NextColumn();
    1762          }
    1763          ImGui::Columns(1);
    1764          if (h_borders)
     3264        }
     3265        ImGui::Columns(1);
     3266        if (h_borders)
    17653267            ImGui::Separator();
    1766          ImGui::TreePop();
    1767       }
    1768 
    1769       // Scrolling columns
    1770       /*
    1771       if (ImGui::TreeNode("Vertical Scrolling"))
    1772       {
    1773       ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y));
    1774       ImGui::Columns(3);
    1775       ImGui::Text("ID"); ImGui::NextColumn();
    1776       ImGui::Text("Name"); ImGui::NextColumn();
    1777       ImGui::Text("Path"); ImGui::NextColumn();
    1778       ImGui::Columns(1);
    1779       ImGui::Separator();
    1780       ImGui::EndChild();
    1781       ImGui::BeginChild("##scrollingregion", ImVec2(0, 60));
    1782       ImGui::Columns(3);
    1783       for (int i = 0; i < 10; i++)
    1784       {
    1785       ImGui::Text("%04d", i); ImGui::NextColumn();
    1786       ImGui::Text("Foobar"); ImGui::NextColumn();
    1787       ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn();
    1788       }
    1789       ImGui::Columns(1);
    1790       ImGui::EndChild();
    1791       ImGui::TreePop();
    1792       }
    1793       */
    1794 
    1795       if (ImGui::TreeNode("Horizontal Scrolling"))
    1796       {
    1797          ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
    1798          ImGui::BeginChild("##ScrollingRegion", ImVec2(0, ImGui::GetFontSize() * 20), false, ImGuiWindowFlags_HorizontalScrollbar);
    1799          ImGui::Columns(10);
    1800          int ITEMS_COUNT = 2000;
    1801          ImGuiListClipper clipper(ITEMS_COUNT);  // Also demonstrate using the clipper for large list
    1802          while (clipper.Step())
    1803          {
     3268        ImGui::TreePop();
     3269    }
     3270
     3271    // Create multiple items in a same cell before switching to next column
     3272    if (ImGui::TreeNode("Mixed items"))
     3273    {
     3274        ImGui::Columns(3, "mixed");
     3275        ImGui::Separator();
     3276
     3277        ImGui::Text("Hello");
     3278        ImGui::Button("Banana");
     3279        ImGui::NextColumn();
     3280
     3281        ImGui::Text("ImGui");
     3282        ImGui::Button("Apple");
     3283        static float foo = 1.0f;
     3284        ImGui::InputFloat("red", &foo, 0.05f, 0, "%.3f");
     3285        ImGui::Text("An extra line here.");
     3286        ImGui::NextColumn();
     3287
     3288        ImGui::Text("Sailor");
     3289        ImGui::Button("Corniflower");
     3290        static float bar = 1.0f;
     3291        ImGui::InputFloat("blue", &bar, 0.05f, 0, "%.3f");
     3292        ImGui::NextColumn();
     3293
     3294        if (ImGui::CollapsingHeader("Category A")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
     3295        if (ImGui::CollapsingHeader("Category B")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
     3296        if (ImGui::CollapsingHeader("Category C")) { ImGui::Text("Blah blah blah"); } ImGui::NextColumn();
     3297        ImGui::Columns(1);
     3298        ImGui::Separator();
     3299        ImGui::TreePop();
     3300    }
     3301
     3302    // Word wrapping
     3303    if (ImGui::TreeNode("Word-wrapping"))
     3304    {
     3305        ImGui::Columns(2, "word-wrapping");
     3306        ImGui::Separator();
     3307        ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
     3308        ImGui::TextWrapped("Hello Left");
     3309        ImGui::NextColumn();
     3310        ImGui::TextWrapped("The quick brown fox jumps over the lazy dog.");
     3311        ImGui::TextWrapped("Hello Right");
     3312        ImGui::Columns(1);
     3313        ImGui::Separator();
     3314        ImGui::TreePop();
     3315    }
     3316
     3317    // Scrolling columns
     3318    /*
     3319    if (ImGui::TreeNode("Vertical Scrolling"))
     3320    {
     3321        ImGui::BeginChild("##header", ImVec2(0, ImGui::GetTextLineHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y));
     3322        ImGui::Columns(3);
     3323        ImGui::Text("ID"); ImGui::NextColumn();
     3324        ImGui::Text("Name"); ImGui::NextColumn();
     3325        ImGui::Text("Path"); ImGui::NextColumn();
     3326        ImGui::Columns(1);
     3327        ImGui::Separator();
     3328        ImGui::EndChild();
     3329        ImGui::BeginChild("##scrollingregion", ImVec2(0, 60));
     3330        ImGui::Columns(3);
     3331        for (int i = 0; i < 10; i++)
     3332        {
     3333            ImGui::Text("%04d", i); ImGui::NextColumn();
     3334            ImGui::Text("Foobar"); ImGui::NextColumn();
     3335            ImGui::Text("/path/foobar/%04d/", i); ImGui::NextColumn();
     3336        }
     3337        ImGui::Columns(1);
     3338        ImGui::EndChild();
     3339        ImGui::TreePop();
     3340    }
     3341    */
     3342
     3343    if (ImGui::TreeNode("Horizontal Scrolling"))
     3344    {
     3345        ImGui::SetNextWindowContentSize(ImVec2(1500.0f, 0.0f));
     3346        ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
     3347        ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar);
     3348        ImGui::Columns(10);
     3349        int ITEMS_COUNT = 2000;
     3350        ImGuiListClipper clipper; // Also demonstrate using the clipper for large list
     3351        clipper.Begin(ITEMS_COUNT);
     3352        while (clipper.Step())
     3353        {
    18043354            for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
    1805                for (int j = 0; j < 10; j++)
    1806                {
    1807                   ImGui::Text("Line %d Column %d...", i, j);
    1808                   ImGui::NextColumn();
    1809                }
    1810          }
    1811          ImGui::Columns(1);
    1812          ImGui::EndChild();
    1813          ImGui::TreePop();
    1814       }
    1815 
    1816       bool node_open = ImGui::TreeNode("Tree within single cell");
    1817       ImGui::SameLine(); ShowHelpMarker("NB: Tree node must be poped before ending the cell. There's no storage of state per-cell.");
    1818       if (node_open)
    1819       {
    1820          ImGui::Columns(2, "tree items");
    1821          ImGui::Separator();
    1822          if (ImGui::TreeNode("Hello")) { ImGui::BulletText("Sailor"); ImGui::TreePop(); } ImGui::NextColumn();
    1823          if (ImGui::TreeNode("Bonjour")) { ImGui::BulletText("Marin"); ImGui::TreePop(); } ImGui::NextColumn();
    1824          ImGui::Columns(1);
    1825          ImGui::Separator();
    1826          ImGui::TreePop();
    1827       }
    1828       ImGui::PopID();
    1829    }
    1830 
    1831    if (ImGui::CollapsingHeader("Filtering"))
    1832    {
    1833       static ImGuiTextFilter filter;
    1834       ImGui::Text("Filter usage:\n"
    1835          "  \"\"         display all lines\n"
    1836          "  \"xxx\"      display lines containing \"xxx\"\n"
    1837          "  \"xxx,yyy\"  display lines containing \"xxx\" or \"yyy\"\n"
    1838          "  \"-xxx\"     hide lines containing \"xxx\"");
    1839       filter.Draw();
    1840       const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
    1841       for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
    1842          if (filter.PassFilter(lines[i]))
    1843             ImGui::BulletText("%s", lines[i]);
    1844    }
    1845 
    1846    if (ImGui::CollapsingHeader("Inputs, Navigation & Focus"))
    1847    {
    1848       ImGuiIO& io = ImGui::GetIO();
    1849 
    1850       ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse);
    1851       ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
    1852       ImGui::Text("WantTextInput: %d", io.WantTextInput);
    1853       ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos);
    1854       ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible);
    1855 
    1856       ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
    1857       ImGui::SameLine(); ShowHelpMarker("Instruct ImGui to render a mouse cursor for you in software. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
    1858 
    1859       ImGui::CheckboxFlags("io.ConfigFlags: NavEnableGamepad", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableGamepad);
    1860       ImGui::CheckboxFlags("io.ConfigFlags: NavEnableKeyboard", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableKeyboard);
    1861       ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
    1862       ImGui::SameLine(); ShowHelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
    1863       ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
    1864       ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility.");
    1865 
    1866       if (ImGui::TreeNode("Keyboard, Mouse & Navigation State"))
    1867       {
    1868          if (ImGui::IsMousePosValid())
    1869             ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
    1870          else
    1871             ImGui::Text("Mouse pos: <INVALID>");
    1872          ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
    1873          ImGui::Text("Mouse down:");     for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
    1874          ImGui::Text("Mouse clicked:");  for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
    1875          ImGui::Text("Mouse dbl-clicked:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
    1876          ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i)) { ImGui::SameLine(); ImGui::Text("b%d", i); }
    1877          ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
    1878 
    1879          ImGui::Text("Keys down:");      for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("%d (%.02f secs)", i, io.KeysDownDuration[i]); }
    1880          ImGui::Text("Keys pressed:");   for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i)) { ImGui::SameLine(); ImGui::Text("%d", i); }
    1881          ImGui::Text("Keys release:");   for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i)) { ImGui::SameLine(); ImGui::Text("%d", i); }
    1882          ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
    1883 
    1884          ImGui::Text("NavInputs down:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); }
    1885          ImGui::Text("NavInputs pressed:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); }
    1886          ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); }
    1887 
    1888          ImGui::Button("Hovering me sets the\nkeyboard capture flag");
    1889          if (ImGui::IsItemHovered())
    1890             ImGui::CaptureKeyboardFromApp(true);
    1891          ImGui::SameLine();
    1892          ImGui::Button("Holding me clears the\nthe keyboard capture flag");
    1893          if (ImGui::IsItemActive())
    1894             ImGui::CaptureKeyboardFromApp(false);
    1895 
    1896          ImGui::TreePop();
    1897       }
    1898 
    1899       if (ImGui::TreeNode("Tabbing"))
    1900       {
    1901          ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
    1902          static char buf[32] = "dummy";
    1903          ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
    1904          ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
    1905          ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
    1906          ImGui::PushAllowKeyboardFocus(false);
    1907          ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
    1908          //ImGui::SameLine(); ShowHelperMarker("Use ImGui::PushAllowKeyboardFocus(bool)\nto disable tabbing through certain widgets.");
    1909          ImGui::PopAllowKeyboardFocus();
    1910          ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
    1911          ImGui::TreePop();
    1912       }
    1913 
    1914       if (ImGui::TreeNode("Focus from code"))
    1915       {
    1916          bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
    1917          bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
    1918          bool focus_3 = ImGui::Button("Focus on 3");
    1919          int has_focus = 0;
    1920          static char buf[128] = "click on a button to set focus";
    1921 
    1922          if (focus_1) ImGui::SetKeyboardFocusHere();
    1923          ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
    1924          if (ImGui::IsItemActive()) has_focus = 1;
    1925 
    1926          if (focus_2) ImGui::SetKeyboardFocusHere();
    1927          ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
    1928          if (ImGui::IsItemActive()) has_focus = 2;
    1929 
    1930          ImGui::PushAllowKeyboardFocus(false);
    1931          if (focus_3) ImGui::SetKeyboardFocusHere();
    1932          ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
    1933          if (ImGui::IsItemActive()) has_focus = 3;
    1934          ImGui::PopAllowKeyboardFocus();
    1935 
    1936          if (has_focus)
    1937             ImGui::Text("Item with focus: %d", has_focus);
    1938          else
    1939             ImGui::Text("Item with focus: <none>");
    1940 
    1941          // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
    1942          static float f3[3] = { 0.0f, 0.0f, 0.0f };
    1943          int focus_ahead = -1;
    1944          if (ImGui::Button("Focus on X")) focus_ahead = 0; ImGui::SameLine();
    1945          if (ImGui::Button("Focus on Y")) focus_ahead = 1; ImGui::SameLine();
    1946          if (ImGui::Button("Focus on Z")) focus_ahead = 2;
    1947          if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
    1948          ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
    1949 
    1950          ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
    1951          ImGui::TreePop();
    1952       }
    1953 
    1954       if (ImGui::TreeNode("Focused & Hovered Test"))
    1955       {
    1956          static bool embed_all_inside_a_child_window = false;
    1957          ImGui::Checkbox("Embed everything inside a child window (for additional testing)", &embed_all_inside_a_child_window);
    1958          if (embed_all_inside_a_child_window)
    1959             ImGui::BeginChild("embeddingchild", ImVec2(0, ImGui::GetFontSize() * 25), true);
    1960 
    1961          // Testing IsWindowFocused() function with its various flags (note that the flags can be combined)
    1962          ImGui::BulletText(
    1963             "IsWindowFocused() = %d\n"
    1964             "IsWindowFocused(_ChildWindows) = %d\n"
    1965             "IsWindowFocused(_ChildWindows|_RootWindow) = %d\n"
    1966             "IsWindowFocused(_RootWindow) = %d\n"
    1967             "IsWindowFocused(_AnyWindow) = %d\n",
    1968             ImGui::IsWindowFocused(),
    1969             ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows),
    1970             ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows | ImGuiFocusedFlags_RootWindow),
    1971             ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
    1972             ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
    1973 
    1974          // Testing IsWindowHovered() function with its various flags (note that the flags can be combined)
    1975          ImGui::BulletText(
    1976             "IsWindowHovered() = %d\n"
    1977             "IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
    1978             "IsWindowHovered(_AllowWhenBlockedByActiveItem) = %d\n"
    1979             "IsWindowHovered(_ChildWindows) = %d\n"
    1980             "IsWindowHovered(_ChildWindows|_RootWindow) = %d\n"
    1981             "IsWindowHovered(_RootWindow) = %d\n"
    1982             "IsWindowHovered(_AnyWindow) = %d\n",
    1983             ImGui::IsWindowHovered(),
    1984             ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
    1985             ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
    1986             ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows),
    1987             ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_RootWindow),
    1988             ImGui::IsWindowHovered(ImGuiHoveredFlags_RootWindow),
    1989             ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow));
    1990 
    1991          // Testing IsItemHovered() function (because BulletText is an item itself and that would affect the output of IsItemHovered, we pass all lines in a single items to shorten the code)
    1992          ImGui::Button("ITEM");
    1993          ImGui::BulletText(
    1994             "IsItemHovered() = %d\n"
    1995             "IsItemHovered(_AllowWhenBlockedByPopup) = %d\n"
    1996             "IsItemHovered(_AllowWhenBlockedByActiveItem) = %d\n"
    1997             "IsItemHovered(_AllowWhenOverlapped) = %d\n"
    1998             "IsItemhovered(_RectOnly) = %d\n",
    1999             ImGui::IsItemHovered(),
    2000             ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup),
    2001             ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem),
    2002             ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped),
    2003             ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly));
    2004 
    2005          ImGui::BeginChild("child", ImVec2(0, 50), true);
    2006          ImGui::Text("This is another child window for testing IsWindowHovered() flags.");
    2007          ImGui::EndChild();
    2008 
    2009          if (embed_all_inside_a_child_window)
    2010             EndChild();
    2011 
    2012          ImGui::TreePop();
    2013       }
    2014 
    2015       if (ImGui::TreeNode("Dragging"))
    2016       {
    2017          ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
    2018          for (int button = 0; button < 3; button++)
    2019             ImGui::Text("IsMouseDragging(%d):\n  w/ default threshold: %d,\n  w/ zero threshold: %d\n  w/ large threshold: %d",
    2020                button, ImGui::IsMouseDragging(button), ImGui::IsMouseDragging(button, 0.0f), ImGui::IsMouseDragging(button, 20.0f));
    2021          ImGui::Button("Drag Me");
    2022          if (ImGui::IsItemActive())
    2023          {
    2024             // Draw a line between the button and the mouse cursor
    2025             ImDrawList* draw_list = ImGui::GetWindowDrawList();
    2026             draw_list->PushClipRectFullScreen();
    2027             draw_list->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f);
    2028             draw_list->PopClipRect();
    2029 
    2030             // Drag operations gets "unlocked" when the mouse has moved past a certain threshold (the default threshold is stored in io.MouseDragThreshold)
    2031             // You can request a lower or higher threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta()
     3355                for (int j = 0; j < 10; j++)
     3356                {
     3357                    ImGui::Text("Line %d Column %d...", i, j);
     3358                    ImGui::NextColumn();
     3359                }
     3360        }
     3361        ImGui::Columns(1);
     3362        ImGui::EndChild();
     3363        ImGui::TreePop();
     3364    }
     3365
     3366    if (ImGui::TreeNode("Tree"))
     3367    {
     3368        ImGui::Columns(2, "tree", true);
     3369        for (int x = 0; x < 3; x++)
     3370        {
     3371            bool open1 = ImGui::TreeNode((void*)(intptr_t)x, "Node%d", x);
     3372            ImGui::NextColumn();
     3373            ImGui::Text("Node contents");
     3374            ImGui::NextColumn();
     3375            if (open1)
     3376            {
     3377                for (int y = 0; y < 3; y++)
     3378                {
     3379                    bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
     3380                    ImGui::NextColumn();
     3381                    ImGui::Text("Node contents");
     3382                    if (open2)
     3383                    {
     3384                        ImGui::Text("Even more contents");
     3385                        if (ImGui::TreeNode("Tree in column"))
     3386                        {
     3387                            ImGui::Text("The quick brown fox jumps over the lazy dog");
     3388                            ImGui::TreePop();
     3389                        }
     3390                    }
     3391                    ImGui::NextColumn();
     3392                    if (open2)
     3393                        ImGui::TreePop();
     3394                }
     3395                ImGui::TreePop();
     3396            }
     3397        }
     3398        ImGui::Columns(1);
     3399        ImGui::TreePop();
     3400    }
     3401
     3402    if (disable_indent)
     3403        ImGui::PopStyleVar();
     3404    ImGui::PopID();
     3405}
     3406
     3407static void ShowDemoWindowMisc()
     3408{
     3409    if (ImGui::CollapsingHeader("Filtering"))
     3410    {
     3411        // Helper class to easy setup a text filter.
     3412        // You may want to implement a more feature-full filtering scheme in your own application.
     3413        static ImGuiTextFilter filter;
     3414        ImGui::Text("Filter usage:\n"
     3415                    "  \"\"         display all lines\n"
     3416                    "  \"xxx\"      display lines containing \"xxx\"\n"
     3417                    "  \"xxx,yyy\"  display lines containing \"xxx\" or \"yyy\"\n"
     3418                    "  \"-xxx\"     hide lines containing \"xxx\"");
     3419        filter.Draw();
     3420        const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
     3421        for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
     3422            if (filter.PassFilter(lines[i]))
     3423                ImGui::BulletText("%s", lines[i]);
     3424    }
     3425
     3426    if (ImGui::CollapsingHeader("Inputs, Navigation & Focus"))
     3427    {
     3428        ImGuiIO& io = ImGui::GetIO();
     3429
     3430        // Display ImGuiIO output flags
     3431        ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse);
     3432        ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
     3433        ImGui::Text("WantTextInput: %d", io.WantTextInput);
     3434        ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos);
     3435        ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible);
     3436
     3437        // Display Keyboard/Mouse state
     3438        if (ImGui::TreeNode("Keyboard, Mouse & Navigation State"))
     3439        {
     3440            if (ImGui::IsMousePosValid())
     3441                ImGui::Text("Mouse pos: (%g, %g)", io.MousePos.x, io.MousePos.y);
     3442            else
     3443                ImGui::Text("Mouse pos: <INVALID>");
     3444            ImGui::Text("Mouse delta: (%g, %g)", io.MouseDelta.x, io.MouseDelta.y);
     3445            ImGui::Text("Mouse down:");     for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (io.MouseDownDuration[i] >= 0.0f)   { ImGui::SameLine(); ImGui::Text("b%d (%.02f secs)", i, io.MouseDownDuration[i]); }
     3446            ImGui::Text("Mouse clicked:");  for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseClicked(i))          { ImGui::SameLine(); ImGui::Text("b%d", i); }
     3447            ImGui::Text("Mouse dblclick:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseDoubleClicked(i))    { ImGui::SameLine(); ImGui::Text("b%d", i); }
     3448            ImGui::Text("Mouse released:"); for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) if (ImGui::IsMouseReleased(i))         { ImGui::SameLine(); ImGui::Text("b%d", i); }
     3449            ImGui::Text("Mouse wheel: %.1f", io.MouseWheel);
     3450
     3451            ImGui::Text("Keys down:");      for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (io.KeysDownDuration[i] >= 0.0f)     { ImGui::SameLine(); ImGui::Text("%d (0x%X) (%.02f secs)", i, i, io.KeysDownDuration[i]); }
     3452            ImGui::Text("Keys pressed:");   for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyPressed(i))             { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); }
     3453            ImGui::Text("Keys release:");   for (int i = 0; i < IM_ARRAYSIZE(io.KeysDown); i++) if (ImGui::IsKeyReleased(i))            { ImGui::SameLine(); ImGui::Text("%d (0x%X)", i, i); }
     3454            ImGui::Text("Keys mods: %s%s%s%s", io.KeyCtrl ? "CTRL " : "", io.KeyShift ? "SHIFT " : "", io.KeyAlt ? "ALT " : "", io.KeySuper ? "SUPER " : "");
     3455            ImGui::Text("Chars queue:");    for (int i = 0; i < io.InputQueueCharacters.Size; i++) { ImWchar c = io.InputQueueCharacters[i]; ImGui::SameLine();  ImGui::Text("\'%c\' (0x%04X)", (c > ' ' && c <= 255) ? (char)c : '?', c); } // FIXME: We should convert 'c' to UTF-8 here but the functions are not public.
     3456
     3457            ImGui::Text("NavInputs down:");     for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputs[i] > 0.0f)              { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputs[i]); }
     3458            ImGui::Text("NavInputs pressed:");  for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] == 0.0f) { ImGui::SameLine(); ImGui::Text("[%d]", i); }
     3459            ImGui::Text("NavInputs duration:"); for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++) if (io.NavInputsDownDuration[i] >= 0.0f) { ImGui::SameLine(); ImGui::Text("[%d] %.2f", i, io.NavInputsDownDuration[i]); }
     3460
     3461            ImGui::Button("Hovering me sets the\nkeyboard capture flag");
     3462            if (ImGui::IsItemHovered())
     3463                ImGui::CaptureKeyboardFromApp(true);
     3464            ImGui::SameLine();
     3465            ImGui::Button("Holding me clears the\nthe keyboard capture flag");
     3466            if (ImGui::IsItemActive())
     3467                ImGui::CaptureKeyboardFromApp(false);
     3468
     3469            ImGui::TreePop();
     3470        }
     3471
     3472        if (ImGui::TreeNode("Tabbing"))
     3473        {
     3474            ImGui::Text("Use TAB/SHIFT+TAB to cycle through keyboard editable fields.");
     3475            static char buf[32] = "hello";
     3476            ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
     3477            ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
     3478            ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
     3479            ImGui::PushAllowKeyboardFocus(false);
     3480            ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
     3481            //ImGui::SameLine(); HelpMarker("Use ImGui::PushAllowKeyboardFocus(bool) to disable tabbing through certain widgets.");
     3482            ImGui::PopAllowKeyboardFocus();
     3483            ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
     3484            ImGui::TreePop();
     3485        }
     3486
     3487        if (ImGui::TreeNode("Focus from code"))
     3488        {
     3489            bool focus_1 = ImGui::Button("Focus on 1"); ImGui::SameLine();
     3490            bool focus_2 = ImGui::Button("Focus on 2"); ImGui::SameLine();
     3491            bool focus_3 = ImGui::Button("Focus on 3");
     3492            int has_focus = 0;
     3493            static char buf[128] = "click on a button to set focus";
     3494
     3495            if (focus_1) ImGui::SetKeyboardFocusHere();
     3496            ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
     3497            if (ImGui::IsItemActive()) has_focus = 1;
     3498
     3499            if (focus_2) ImGui::SetKeyboardFocusHere();
     3500            ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
     3501            if (ImGui::IsItemActive()) has_focus = 2;
     3502
     3503            ImGui::PushAllowKeyboardFocus(false);
     3504            if (focus_3) ImGui::SetKeyboardFocusHere();
     3505            ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
     3506            if (ImGui::IsItemActive()) has_focus = 3;
     3507            ImGui::PopAllowKeyboardFocus();
     3508
     3509            if (has_focus)
     3510                ImGui::Text("Item with focus: %d", has_focus);
     3511            else
     3512                ImGui::Text("Item with focus: <none>");
     3513
     3514            // Use >= 0 parameter to SetKeyboardFocusHere() to focus an upcoming item
     3515            static float f3[3] = { 0.0f, 0.0f, 0.0f };
     3516            int focus_ahead = -1;
     3517            if (ImGui::Button("Focus on X")) { focus_ahead = 0; } ImGui::SameLine();
     3518            if (ImGui::Button("Focus on Y")) { focus_ahead = 1; } ImGui::SameLine();
     3519            if (ImGui::Button("Focus on Z")) { focus_ahead = 2; }
     3520            if (focus_ahead != -1) ImGui::SetKeyboardFocusHere(focus_ahead);
     3521            ImGui::SliderFloat3("Float3", &f3[0], 0.0f, 1.0f);
     3522
     3523            ImGui::TextWrapped("NB: Cursor & selection are preserved when refocusing last used item in code.");
     3524            ImGui::TreePop();
     3525        }
     3526
     3527        if (ImGui::TreeNode("Dragging"))
     3528        {
     3529            ImGui::TextWrapped("You can use ImGui::GetMouseDragDelta(0) to query for the dragged amount on any widget.");
     3530            for (int button = 0; button < 3; button++)
     3531            {
     3532                ImGui::Text("IsMouseDragging(%d):", button);
     3533                ImGui::Text("  w/ default threshold: %d,", ImGui::IsMouseDragging(button));
     3534                ImGui::Text("  w/ zero threshold: %d,", ImGui::IsMouseDragging(button, 0.0f));
     3535                ImGui::Text("  w/ large threshold: %d,", ImGui::IsMouseDragging(button, 20.0f));
     3536            }
     3537
     3538            ImGui::Button("Drag Me");
     3539            if (ImGui::IsItemActive())
     3540                ImGui::GetForegroundDrawList()->AddLine(io.MouseClickedPos[0], io.MousePos, ImGui::GetColorU32(ImGuiCol_Button), 4.0f); // Draw a line between the button and the mouse cursor
     3541
     3542            // Drag operations gets "unlocked" when the mouse has moved past a certain threshold
     3543            // (the default threshold is stored in io.MouseDragThreshold). You can request a lower or higher
     3544            // threshold using the second parameter of IsMouseDragging() and GetMouseDragDelta().
    20323545            ImVec2 value_raw = ImGui::GetMouseDragDelta(0, 0.0f);
    20333546            ImVec2 value_with_lock_threshold = ImGui::GetMouseDragDelta(0);
    20343547            ImVec2 mouse_delta = io.MouseDelta;
    2035             ImGui::SameLine(); ImGui::Text("Raw (%.1f, %.1f), WithLockThresold (%.1f, %.1f), MouseDelta (%.1f, %.1f)", value_raw.x, value_raw.y, value_with_lock_threshold.x, value_with_lock_threshold.y, mouse_delta.x, mouse_delta.y);
    2036          }
    2037          ImGui::TreePop();
    2038       }
    2039 
    2040       if (ImGui::TreeNode("Mouse cursors"))
    2041       {
    2042          const char* mouse_cursors_names[] = { "Arrow", "TextInput", "Move", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE" };
    2043          IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
    2044 
    2045          ImGui::Text("Current mouse cursor = %d: %s", ImGui::GetMouseCursor(), mouse_cursors_names[ImGui::GetMouseCursor()]);
    2046          ImGui::Text("Hover to see mouse cursors:");
    2047          ImGui::SameLine(); ShowHelpMarker("Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, otherwise your backend needs to handle it.");
    2048          for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
    2049          {
    2050             char label[32];
    2051             sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
    2052             ImGui::Bullet(); ImGui::Selectable(label, false);
    2053             if (ImGui::IsItemHovered() || ImGui::IsItemFocused())
    2054                ImGui::SetMouseCursor(i);
    2055          }
    2056          ImGui::TreePop();
    2057       }
    2058    }
    2059 
    2060    ImGui::End();
     3548            ImGui::Text("GetMouseDragDelta(0):");
     3549            ImGui::Text("  w/ default threshold: (%.1f, %.1f)", value_with_lock_threshold.x, value_with_lock_threshold.y);
     3550            ImGui::Text("  w/ zero threshold: (%.1f, %.1f)", value_raw.x, value_raw.y);
     3551            ImGui::Text("io.MouseDelta: (%.1f, %.1f)", mouse_delta.x, mouse_delta.y);
     3552            ImGui::TreePop();
     3553        }
     3554
     3555        if (ImGui::TreeNode("Mouse cursors"))
     3556        {
     3557            const char* mouse_cursors_names[] = { "Arrow", "TextInput", "ResizeAll", "ResizeNS", "ResizeEW", "ResizeNESW", "ResizeNWSE", "Hand", "NotAllowed" };
     3558            IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
     3559
     3560            ImGuiMouseCursor current = ImGui::GetMouseCursor();
     3561            ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
     3562            ImGui::Text("Hover to see mouse cursors:");
     3563            ImGui::SameLine(); HelpMarker(
     3564                "Your application can render a different mouse cursor based on what ImGui::GetMouseCursor() returns. "
     3565                "If software cursor rendering (io.MouseDrawCursor) is set ImGui will draw the right cursor for you, "
     3566                "otherwise your backend needs to handle it.");
     3567            for (int i = 0; i < ImGuiMouseCursor_COUNT; i++)
     3568            {
     3569                char label[32];
     3570                sprintf(label, "Mouse cursor %d: %s", i, mouse_cursors_names[i]);
     3571                ImGui::Bullet(); ImGui::Selectable(label, false);
     3572                if (ImGui::IsItemHovered() || ImGui::IsItemFocused())
     3573                    ImGui::SetMouseCursor(i);
     3574            }
     3575            ImGui::TreePop();
     3576        }
     3577    }
    20613578}
    20623579
     3580//-----------------------------------------------------------------------------
     3581// [SECTION] About Window / ShowAboutWindow()
     3582// Access from Dear ImGui Demo -> Tools -> About
     3583//-----------------------------------------------------------------------------
     3584
     3585void ImGui::ShowAboutWindow(bool* p_open)
     3586{
     3587    if (!ImGui::Begin("About Dear ImGui", p_open, ImGuiWindowFlags_AlwaysAutoResize))
     3588    {
     3589        ImGui::End();
     3590        return;
     3591    }
     3592    ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
     3593    ImGui::Separator();
     3594    ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
     3595    ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
     3596
     3597    static bool show_config_info = false;
     3598    ImGui::Checkbox("Config/Build Information", &show_config_info);
     3599    if (show_config_info)
     3600    {
     3601        ImGuiIO& io = ImGui::GetIO();
     3602        ImGuiStyle& style = ImGui::GetStyle();
     3603
     3604        bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
     3605        ImVec2 child_size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18);
     3606        ImGui::BeginChildFrame(ImGui::GetID("cfg_infos"), child_size, ImGuiWindowFlags_NoMove);
     3607        if (copy_to_clipboard)
     3608        {
     3609            ImGui::LogToClipboard();
     3610            ImGui::LogText("```\n"); // Back quotes will make text appears without formatting when pasting on GitHub
     3611        }
     3612
     3613        ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
     3614        ImGui::Separator();
     3615        ImGui::Text("sizeof(size_t): %d, sizeof(ImDrawIdx): %d, sizeof(ImDrawVert): %d", (int)sizeof(size_t), (int)sizeof(ImDrawIdx), (int)sizeof(ImDrawVert));
     3616        ImGui::Text("define: __cplusplus=%d", (int)__cplusplus);
     3617#ifdef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     3618        ImGui::Text("define: IMGUI_DISABLE_OBSOLETE_FUNCTIONS");
     3619#endif
     3620#ifdef IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
     3621        ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS");
     3622#endif
     3623#ifdef IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
     3624        ImGui::Text("define: IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS");
     3625#endif
     3626#ifdef IMGUI_DISABLE_WIN32_FUNCTIONS
     3627        ImGui::Text("define: IMGUI_DISABLE_WIN32_FUNCTIONS");
     3628#endif
     3629#ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
     3630        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS");
     3631#endif
     3632#ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
     3633        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS");
     3634#endif
     3635#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
     3636        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS");
     3637#endif
     3638#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
     3639        ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS");
     3640#endif
     3641#ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS
     3642        ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS");
     3643#endif
     3644#ifdef IMGUI_USE_BGRA_PACKED_COLOR
     3645        ImGui::Text("define: IMGUI_USE_BGRA_PACKED_COLOR");
     3646#endif
     3647#ifdef _WIN32
     3648        ImGui::Text("define: _WIN32");
     3649#endif
     3650#ifdef _WIN64
     3651        ImGui::Text("define: _WIN64");
     3652#endif
     3653#ifdef __linux__
     3654        ImGui::Text("define: __linux__");
     3655#endif
     3656#ifdef __APPLE__
     3657        ImGui::Text("define: __APPLE__");
     3658#endif
     3659#ifdef _MSC_VER
     3660        ImGui::Text("define: _MSC_VER=%d", _MSC_VER);
     3661#endif
     3662#ifdef __MINGW32__
     3663        ImGui::Text("define: __MINGW32__");
     3664#endif
     3665#ifdef __MINGW64__
     3666        ImGui::Text("define: __MINGW64__");
     3667#endif
     3668#ifdef __GNUC__
     3669        ImGui::Text("define: __GNUC__=%d", (int)__GNUC__);
     3670#endif
     3671#ifdef __clang_version__
     3672        ImGui::Text("define: __clang_version__=%s", __clang_version__);
     3673#endif
     3674        ImGui::Separator();
     3675        ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
     3676        ImGui::Text("io.BackendRendererName: %s", io.BackendRendererName ? io.BackendRendererName : "NULL");
     3677        ImGui::Text("io.ConfigFlags: 0x%08X", io.ConfigFlags);
     3678        if (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)        ImGui::Text(" NavEnableKeyboard");
     3679        if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad)         ImGui::Text(" NavEnableGamepad");
     3680        if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos)     ImGui::Text(" NavEnableSetMousePos");
     3681        if (io.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard)     ImGui::Text(" NavNoCaptureKeyboard");
     3682        if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)                  ImGui::Text(" NoMouse");
     3683        if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)      ImGui::Text(" NoMouseCursorChange");
     3684        if (io.MouseDrawCursor)                                         ImGui::Text("io.MouseDrawCursor");
     3685        if (io.ConfigMacOSXBehaviors)                                   ImGui::Text("io.ConfigMacOSXBehaviors");
     3686        if (io.ConfigInputTextCursorBlink)                              ImGui::Text("io.ConfigInputTextCursorBlink");
     3687        if (io.ConfigWindowsResizeFromEdges)                            ImGui::Text("io.ConfigWindowsResizeFromEdges");
     3688        if (io.ConfigWindowsMoveFromTitleBarOnly)                       ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
     3689        if (io.ConfigWindowsMemoryCompactTimer >= 0.0f)                 ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer);
     3690        ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
     3691        if (io.BackendFlags & ImGuiBackendFlags_HasGamepad)             ImGui::Text(" HasGamepad");
     3692        if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors)        ImGui::Text(" HasMouseCursors");
     3693        if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos)         ImGui::Text(" HasSetMousePos");
     3694        if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)   ImGui::Text(" RendererHasVtxOffset");
     3695        ImGui::Separator();
     3696        ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
     3697        ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
     3698        ImGui::Text("io.DisplayFramebufferScale: %.2f,%.2f", io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
     3699        ImGui::Separator();
     3700        ImGui::Text("style.WindowPadding: %.2f,%.2f", style.WindowPadding.x, style.WindowPadding.y);
     3701        ImGui::Text("style.WindowBorderSize: %.2f", style.WindowBorderSize);
     3702        ImGui::Text("style.FramePadding: %.2f,%.2f", style.FramePadding.x, style.FramePadding.y);
     3703        ImGui::Text("style.FrameRounding: %.2f", style.FrameRounding);
     3704        ImGui::Text("style.FrameBorderSize: %.2f", style.FrameBorderSize);
     3705        ImGui::Text("style.ItemSpacing: %.2f,%.2f", style.ItemSpacing.x, style.ItemSpacing.y);
     3706        ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
     3707
     3708        if (copy_to_clipboard)
     3709        {
     3710            ImGui::LogText("\n```\n");
     3711            ImGui::LogFinish();
     3712        }
     3713        ImGui::EndChildFrame();
     3714    }
     3715    ImGui::End();
     3716}
     3717
     3718//-----------------------------------------------------------------------------
     3719// [SECTION] Style Editor / ShowStyleEditor()
     3720//-----------------------------------------------------------------------------
     3721// - ShowStyleSelector()
     3722// - ShowFontSelector()
     3723// - ShowStyleEditor()
     3724//-----------------------------------------------------------------------------
     3725
    20633726// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
    2064 // Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally.
     3727// Here we use the simplified Combo() api that packs items into a single literal string.
     3728// Useful for quick combo boxes where the choices are known locally.
    20653729bool ImGui::ShowStyleSelector(const char* label)
    20663730{
    2067    static int style_idx = -1;
    2068    if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))
    2069    {
    2070       switch (style_idx)
    2071       {
    2072       case 0: ImGui::StyleColorsClassic(); break;
    2073       case 1: ImGui::StyleColorsDark(); break;
    2074       case 2: ImGui::StyleColorsLight(); break;
    2075       }
    2076       return true;
    2077    }
    2078    return false;
     3731    static int style_idx = -1;
     3732    if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))
     3733    {
     3734        switch (style_idx)
     3735        {
     3736        case 0: ImGui::StyleColorsClassic(); break;
     3737        case 1: ImGui::StyleColorsDark(); break;
     3738        case 2: ImGui::StyleColorsLight(); break;
     3739        }
     3740        return true;
     3741    }
     3742    return false;
    20793743}
    20803744
     
    20833747void ImGui::ShowFontSelector(const char* label)
    20843748{
    2085    ImGuiIO& io = ImGui::GetIO();
    2086    ImFont* font_current = ImGui::GetFont();
    2087    if (ImGui::BeginCombo(label, font_current->GetDebugName()))
    2088    {
    2089       for (int n = 0; n < io.Fonts->Fonts.Size; n++)
    2090          if (ImGui::Selectable(io.Fonts->Fonts[n]->GetDebugName(), io.Fonts->Fonts[n] == font_current))
    2091             io.FontDefault = io.Fonts->Fonts[n];
    2092       ImGui::EndCombo();
    2093    }
    2094    ImGui::SameLine();
    2095    ShowHelpMarker(
    2096       "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
    2097       "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
    2098       "- Read FAQ and documentation in misc/fonts/ for more details.\n"
    2099       "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
     3749    ImGuiIO& io = ImGui::GetIO();
     3750    ImFont* font_current = ImGui::GetFont();
     3751    if (ImGui::BeginCombo(label, font_current->GetDebugName()))
     3752    {
     3753        for (int n = 0; n < io.Fonts->Fonts.Size; n++)
     3754        {
     3755            ImFont* font = io.Fonts->Fonts[n];
     3756            ImGui::PushID((void*)font);
     3757            if (ImGui::Selectable(font->GetDebugName(), font == font_current))
     3758                io.FontDefault = font;
     3759            ImGui::PopID();
     3760        }
     3761        ImGui::EndCombo();
     3762    }
     3763    ImGui::SameLine();
     3764    HelpMarker(
     3765        "- Load additional fonts with io.Fonts->AddFontFromFileTTF().\n"
     3766        "- The font atlas is built when calling io.Fonts->GetTexDataAsXXXX() or io.Fonts->Build().\n"
     3767        "- Read FAQ and docs/FONTS.md for more details.\n"
     3768        "- If you need to add/remove fonts at runtime (e.g. for DPI change), do it before calling NewFrame().");
     3769}
     3770
     3771// [Internal] Display details for a single font, called by ShowStyleEditor().
     3772static void NodeFont(ImFont* font)
     3773{
     3774    ImGuiIO& io = ImGui::GetIO();
     3775    ImGuiStyle& style = ImGui::GetStyle();
     3776    bool font_details_opened = ImGui::TreeNode(font, "Font: \"%s\"\n%.2f px, %d glyphs, %d file(s)",
     3777        font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount);
     3778    ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; }
     3779    if (!font_details_opened)
     3780        return;
     3781
     3782    ImGui::PushFont(font);
     3783    ImGui::Text("The quick brown fox jumps over the lazy dog");
     3784    ImGui::PopFont();
     3785    ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f");   // Scale only this font
     3786    ImGui::SameLine(); HelpMarker(
     3787        "Note than the default embedded font is NOT meant to be scaled.\n\n"
     3788        "Font are currently rendered into bitmaps at a given size at the time of building the atlas. "
     3789        "You may oversample them to get some flexibility with scaling. "
     3790        "You can also render at multiple sizes and select which one to use at runtime.\n\n"
     3791        "(Glimmer of hope: the atlas system will be rewritten in the future to make scaling more flexible.)");
     3792    ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
     3793    ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar);
     3794    ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar);
     3795    const int surface_sqrt = (int)sqrtf((float)font->MetricsTotalSurface);
     3796    ImGui::Text("Texture Area: about %d px ~%dx%d px", font->MetricsTotalSurface, surface_sqrt, surface_sqrt);
     3797    for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
     3798        if (font->ConfigData)
     3799            if (const ImFontConfig* cfg = &font->ConfigData[config_i])
     3800                ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d, Offset: (%.1f,%.1f)",
     3801                    config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH, cfg->GlyphOffset.x, cfg->GlyphOffset.y);
     3802    if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
     3803    {
     3804        // Display all glyphs of the fonts in separate pages of 256 characters
     3805        const ImU32 glyph_col = ImGui::GetColorU32(ImGuiCol_Text);
     3806        for (unsigned int base = 0; base <= IM_UNICODE_CODEPOINT_MAX; base += 256)
     3807        {
     3808            // Skip ahead if a large bunch of glyphs are not present in the font (test in chunks of 4k)
     3809            // This is only a small optimization to reduce the number of iterations when IM_UNICODE_MAX_CODEPOINT
     3810            // is large // (if ImWchar==ImWchar32 we will do at least about 272 queries here)
     3811            if (!(base & 4095) && font->IsGlyphRangeUnused(base, base + 4095))
     3812            {
     3813                base += 4096 - 256;
     3814                continue;
     3815            }
     3816
     3817            int count = 0;
     3818            for (unsigned int n = 0; n < 256; n++)
     3819                if (font->FindGlyphNoFallback((ImWchar)(base + n)))
     3820                    count++;
     3821            if (count <= 0)
     3822                continue;
     3823            if (!ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
     3824                continue;
     3825            float cell_size = font->FontSize * 1;
     3826            float cell_spacing = style.ItemSpacing.y;
     3827            ImVec2 base_pos = ImGui::GetCursorScreenPos();
     3828            ImDrawList* draw_list = ImGui::GetWindowDrawList();
     3829            for (unsigned int n = 0; n < 256; n++)
     3830            {
     3831                // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions
     3832                // available here and thus cannot easily generate a zero-terminated UTF-8 encoded string.
     3833                ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
     3834                ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
     3835                const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
     3836                draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
     3837                if (glyph)
     3838                    font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
     3839                if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2))
     3840                {
     3841                    ImGui::BeginTooltip();
     3842                    ImGui::Text("Codepoint: U+%04X", base + n);
     3843                    ImGui::Separator();
     3844                    ImGui::Text("Visible: %d", glyph->Visible);
     3845                    ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX);
     3846                    ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
     3847                    ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
     3848                    ImGui::EndTooltip();
     3849                }
     3850            }
     3851            ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
     3852            ImGui::TreePop();
     3853        }
     3854        ImGui::TreePop();
     3855    }
     3856    ImGui::TreePop();
    21003857}
    21013858
    21023859void ImGui::ShowStyleEditor(ImGuiStyle* ref)
    21033860{
    2104    // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it compares to an internally stored reference)
    2105    ImGuiStyle& style = ImGui::GetStyle();
    2106    static ImGuiStyle ref_saved_style;
    2107 
    2108    // Default to using internal storage as reference
    2109    static bool init = true;
    2110    if (init && ref == NULL)
    2111       ref_saved_style = style;
    2112    init = false;
    2113    if (ref == NULL)
    2114       ref = &ref_saved_style;
    2115 
    2116    ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
    2117 
    2118    if (ImGui::ShowStyleSelector("Colors##Selector"))
    2119       ref_saved_style = style;
    2120    ImGui::ShowFontSelector("Fonts##Selector");
    2121 
    2122    // Simplified Settings
    2123    if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
    2124       style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
    2125    { bool window_border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &window_border)) style.WindowBorderSize = window_border ? 1.0f : 0.0f; }
    2126    ImGui::SameLine();
    2127    { bool frame_border = (style.FrameBorderSize > 0.0f); if (ImGui::Checkbox("FrameBorder", &frame_border)) style.FrameBorderSize = frame_border ? 1.0f : 0.0f; }
    2128    ImGui::SameLine();
    2129    { bool popup_border = (style.PopupBorderSize > 0.0f); if (ImGui::Checkbox("PopupBorder", &popup_border)) style.PopupBorderSize = popup_border ? 1.0f : 0.0f; }
    2130 
    2131    // Save/Revert button
    2132    if (ImGui::Button("Save Ref"))
    2133       *ref = ref_saved_style = style;
    2134    ImGui::SameLine();
    2135    if (ImGui::Button("Revert Ref"))
    2136       style = *ref;
    2137    ImGui::SameLine();
    2138    ShowHelpMarker("Save/Revert in local non-persistent storage. Default Colors definition are not affected. Use \"Export Colors\" below to save them somewhere.");
    2139 
    2140    if (ImGui::TreeNode("Rendering"))
    2141    {
    2142       ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines); ImGui::SameLine(); ShowHelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
    2143       ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
    2144       ImGui::PushItemWidth(100);
    2145       ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, FLT_MAX, NULL, 2.0f);
    2146       if (style.CurveTessellationTol < 0.0f) style.CurveTessellationTol = 0.10f;
    2147       ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
    2148       ImGui::PopItemWidth();
    2149       ImGui::TreePop();
    2150    }
    2151 
    2152    if (ImGui::TreeNode("Settings"))
    2153    {
    2154       ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
    2155       ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f");
    2156       ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
    2157       ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
    2158       ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
    2159       ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
    2160       ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
    2161       ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
    2162       ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
    2163       ImGui::Text("BorderSize");
    2164       ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
    2165       ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
    2166       ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
    2167       ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
    2168       ImGui::Text("Rounding");
    2169       ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f");
    2170       ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f");
    2171       ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
    2172       ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
    2173       ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
    2174       ImGui::Text("Alignment");
    2175       ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
    2176       ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); ShowHelpMarker("Alignment applies when a button is larger than its text content.");
    2177       ImGui::Text("Safe Area Padding"); ImGui::SameLine(); ShowHelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
    2178       ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
    2179       ImGui::TreePop();
    2180    }
    2181 
    2182    if (ImGui::TreeNode("Colors"))
    2183    {
    2184       static int output_dest = 0;
    2185       static bool output_only_modified = true;
    2186       if (ImGui::Button("Export Unsaved"))
    2187       {
    2188          if (output_dest == 0)
    2189             ImGui::LogToClipboard();
    2190          else
    2191             ImGui::LogToTTY();
    2192          ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
    2193          for (int i = 0; i < ImGuiCol_COUNT; i++)
    2194          {
    2195             const ImVec4& col = style.Colors[i];
    2196             const char* name = ImGui::GetStyleColorName(i);
    2197             if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
    2198                ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE, name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
    2199          }
    2200          ImGui::LogFinish();
    2201       }
    2202       ImGui::SameLine(); ImGui::PushItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0"); ImGui::PopItemWidth();
    2203       ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
    2204 
    2205       ImGui::Text("Tip: Left-click on colored square to open color picker,\nRight-click to open edit options menu.");
    2206 
    2207       static ImGuiTextFilter filter;
    2208       filter.Draw("Filter colors", 200);
    2209 
    2210       static ImGuiColorEditFlags alpha_flags = 0;
    2211       ImGui::RadioButton("Opaque", &alpha_flags, 0); ImGui::SameLine();
    2212       ImGui::RadioButton("Alpha", &alpha_flags, ImGuiColorEditFlags_AlphaPreview); ImGui::SameLine();
    2213       ImGui::RadioButton("Both", &alpha_flags, ImGuiColorEditFlags_AlphaPreviewHalf);
    2214 
    2215       ImGui::BeginChild("#colors", ImVec2(0, 300), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
    2216       ImGui::PushItemWidth(-160);
    2217       for (int i = 0; i < ImGuiCol_COUNT; i++)
    2218       {
    2219          const char* name = ImGui::GetStyleColorName(i);
    2220          if (!filter.PassFilter(name))
    2221             continue;
    2222          ImGui::PushID(i);
    2223          ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
    2224          if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
    2225          {
    2226             // Tips: in a real user application, you may want to merge and use an icon font into the main font, so instead of "Save"/"Revert" you'd use icons.
    2227             // Read the FAQ and misc/fonts/README.txt about using icon fonts. It's really easy and super convenient!
    2228             ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) ref->Colors[i] = style.Colors[i];
    2229             ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) style.Colors[i] = ref->Colors[i];
    2230          }
    2231          ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
    2232          ImGui::TextUnformatted(name);
    2233          ImGui::PopID();
    2234       }
    2235       ImGui::PopItemWidth();
    2236       ImGui::EndChild();
    2237 
    2238       ImGui::TreePop();
    2239    }
    2240 
    2241    bool fonts_opened = ImGui::TreeNode("Fonts", "Fonts (%d)", ImGui::GetIO().Fonts->Fonts.Size);
    2242    if (fonts_opened)
    2243    {
    2244       ImFontAtlas* atlas = ImGui::GetIO().Fonts;
    2245       if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
    2246       {
    2247          ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), ImColor(255, 255, 255, 255), ImColor(255, 255, 255, 128));
    2248          ImGui::TreePop();
    2249       }
    2250       ImGui::PushItemWidth(100);
    2251       for (int i = 0; i < atlas->Fonts.Size; i++)
    2252       {
    2253          ImFont* font = atlas->Fonts[i];
    2254          ImGui::PushID(font);
    2255          bool font_details_opened = ImGui::TreeNode(font, "Font %d: \'%s\', %.2f px, %d glyphs", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size);
    2256          ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font;
    2257          if (font_details_opened)
    2258          {
    2259             ImGui::PushFont(font);
    2260             ImGui::Text("The quick brown fox jumps over the lazy dog");
    2261             ImGui::PopFont();
    2262             ImGui::DragFloat("Font scale", &font->Scale, 0.005f, 0.3f, 2.0f, "%.1f");   // Scale only this font
    2263             ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, 0);
    2264             ImGui::SameLine(); ShowHelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)");
    2265             ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
    2266             ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar);
    2267             ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)sqrtf((float)font->MetricsTotalSurface), (int)sqrtf((float)font->MetricsTotalSurface));
    2268             for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
    2269                if (ImFontConfig* cfg = &font->ConfigData[config_i])
    2270                   ImGui::BulletText("Input %d: \'%s\', Oversample: (%d,%d), PixelSnapH: %d", config_i, cfg->Name, cfg->OversampleH, cfg->OversampleV, cfg->PixelSnapH);
    2271             if (ImGui::TreeNode("Glyphs", "Glyphs (%d)", font->Glyphs.Size))
    2272             {
    2273                // Display all glyphs of the fonts in separate pages of 256 characters
    2274                for (int base = 0; base < 0x10000; base += 256)
    2275                {
    2276                   int count = 0;
    2277                   for (int n = 0; n < 256; n++)
    2278                      count += font->FindGlyphNoFallback((ImWchar)(base + n)) ? 1 : 0;
    2279                   if (count > 0 && ImGui::TreeNode((void*)(intptr_t)base, "U+%04X..U+%04X (%d %s)", base, base + 255, count, count > 1 ? "glyphs" : "glyph"))
    2280                   {
    2281                      float cell_size = font->FontSize * 1;
    2282                      float cell_spacing = style.ItemSpacing.y;
    2283                      ImVec2 base_pos = ImGui::GetCursorScreenPos();
    2284                      ImDrawList* draw_list = ImGui::GetWindowDrawList();
    2285                      for (int n = 0; n < 256; n++)
    2286                      {
    2287                         ImVec2 cell_p1(base_pos.x + (n % 16) * (cell_size + cell_spacing), base_pos.y + (n / 16) * (cell_size + cell_spacing));
    2288                         ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
    2289                         const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
    2290                         draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
    2291                         font->RenderChar(draw_list, cell_size, cell_p1, ImGui::GetColorU32(ImGuiCol_Text), (ImWchar)(base + n)); // We use ImFont::RenderChar as a shortcut because we don't have UTF-8 conversion functions available to generate a string.
    2292                         if (glyph && ImGui::IsMouseHoveringRect(cell_p1, cell_p2))
    2293                         {
    2294                            ImGui::BeginTooltip();
    2295                            ImGui::Text("Codepoint: U+%04X", base + n);
    2296                            ImGui::Separator();
    2297                            ImGui::Text("AdvanceX: %.1f", glyph->AdvanceX);
    2298                            ImGui::Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
    2299                            ImGui::Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
    2300                            ImGui::EndTooltip();
    2301                         }
    2302                      }
    2303                      ImGui::Dummy(ImVec2((cell_size + cell_spacing) * 16, (cell_size + cell_spacing) * 16));
    2304                      ImGui::TreePop();
    2305                   }
    2306                }
    2307                ImGui::TreePop();
    2308             }
    2309             ImGui::TreePop();
    2310          }
    2311          ImGui::PopID();
    2312       }
    2313       static float window_scale = 1.0f;
    2314       ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f");              // scale only this window
    2315       ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything
    2316       ImGui::PopItemWidth();
    2317       ImGui::SetWindowFontScale(window_scale);
    2318       ImGui::TreePop();
    2319    }
    2320 
    2321    ImGui::PopItemWidth();
     3861    // You can pass in a reference ImGuiStyle structure to compare to, revert to and save to
     3862    // (without a reference style pointer, we will use one compared locally as a reference)
     3863    ImGuiStyle& style = ImGui::GetStyle();
     3864    static ImGuiStyle ref_saved_style;
     3865
     3866    // Default to using internal storage as reference
     3867    static bool init = true;
     3868    if (init && ref == NULL)
     3869        ref_saved_style = style;
     3870    init = false;
     3871    if (ref == NULL)
     3872        ref = &ref_saved_style;
     3873
     3874    ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.50f);
     3875
     3876    if (ImGui::ShowStyleSelector("Colors##Selector"))
     3877        ref_saved_style = style;
     3878    ImGui::ShowFontSelector("Fonts##Selector");
     3879
     3880    // Simplified Settings (expose floating-pointer border sizes as boolean representing 0.0f or 1.0f)
     3881    if (ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"))
     3882        style.GrabRounding = style.FrameRounding; // Make GrabRounding always the same value as FrameRounding
     3883    { bool border = (style.WindowBorderSize > 0.0f); if (ImGui::Checkbox("WindowBorder", &border)) { style.WindowBorderSize = border ? 1.0f : 0.0f; } }
     3884    ImGui::SameLine();
     3885    { bool border = (style.FrameBorderSize > 0.0f);  if (ImGui::Checkbox("FrameBorder",  &border)) { style.FrameBorderSize  = border ? 1.0f : 0.0f; } }
     3886    ImGui::SameLine();
     3887    { bool border = (style.PopupBorderSize > 0.0f);  if (ImGui::Checkbox("PopupBorder",  &border)) { style.PopupBorderSize  = border ? 1.0f : 0.0f; } }
     3888
     3889    // Save/Revert button
     3890    if (ImGui::Button("Save Ref"))
     3891        *ref = ref_saved_style = style;
     3892    ImGui::SameLine();
     3893    if (ImGui::Button("Revert Ref"))
     3894        style = *ref;
     3895    ImGui::SameLine();
     3896    HelpMarker(
     3897        "Save/Revert in local non-persistent storage. Default Colors definition are not affected. "
     3898        "Use \"Export\" below to save them somewhere.");
     3899
     3900    ImGui::Separator();
     3901
     3902    if (ImGui::BeginTabBar("##tabs", ImGuiTabBarFlags_None))
     3903    {
     3904        if (ImGui::BeginTabItem("Sizes"))
     3905        {
     3906            ImGui::Text("Main");
     3907            ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
     3908            ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
     3909            ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
     3910            ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
     3911            ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
     3912            ImGui::SliderFloat("IndentSpacing", &style.IndentSpacing, 0.0f, 30.0f, "%.0f");
     3913            ImGui::SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
     3914            ImGui::SliderFloat("GrabMinSize", &style.GrabMinSize, 1.0f, 20.0f, "%.0f");
     3915            ImGui::Text("Borders");
     3916            ImGui::SliderFloat("WindowBorderSize", &style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
     3917            ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
     3918            ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
     3919            ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
     3920            ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
     3921            ImGui::Text("Rounding");
     3922            ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
     3923            ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f");
     3924            ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
     3925            ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
     3926            ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
     3927            ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
     3928            ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
     3929            ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
     3930            ImGui::Text("Alignment");
     3931            ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
     3932            int window_menu_button_position = style.WindowMenuButtonPosition + 1;
     3933            if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
     3934                style.WindowMenuButtonPosition = window_menu_button_position - 1;
     3935            ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
     3936            ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
     3937            ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
     3938            ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
     3939            ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
     3940            ImGui::Text("Safe Area Padding");
     3941            ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
     3942            ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
     3943            ImGui::EndTabItem();
     3944        }
     3945
     3946        if (ImGui::BeginTabItem("Colors"))
     3947        {
     3948            static int output_dest = 0;
     3949            static bool output_only_modified = true;
     3950            if (ImGui::Button("Export"))
     3951            {
     3952                if (output_dest == 0)
     3953                    ImGui::LogToClipboard();
     3954                else
     3955                    ImGui::LogToTTY();
     3956                ImGui::LogText("ImVec4* colors = ImGui::GetStyle().Colors;" IM_NEWLINE);
     3957                for (int i = 0; i < ImGuiCol_COUNT; i++)
     3958                {
     3959                    const ImVec4& col = style.Colors[i];
     3960                    const char* name = ImGui::GetStyleColorName(i);
     3961                    if (!output_only_modified || memcmp(&col, &ref->Colors[i], sizeof(ImVec4)) != 0)
     3962                        ImGui::LogText("colors[ImGuiCol_%s]%*s= ImVec4(%.2ff, %.2ff, %.2ff, %.2ff);" IM_NEWLINE,
     3963                            name, 23 - (int)strlen(name), "", col.x, col.y, col.z, col.w);
     3964                }
     3965                ImGui::LogFinish();
     3966            }
     3967            ImGui::SameLine(); ImGui::SetNextItemWidth(120); ImGui::Combo("##output_type", &output_dest, "To Clipboard\0To TTY\0");
     3968            ImGui::SameLine(); ImGui::Checkbox("Only Modified Colors", &output_only_modified);
     3969
     3970            static ImGuiTextFilter filter;
     3971            filter.Draw("Filter colors", ImGui::GetFontSize() * 16);
     3972
     3973            static ImGuiColorEditFlags alpha_flags = 0;
     3974            if (ImGui::RadioButton("Opaque", alpha_flags == ImGuiColorEditFlags_None))             { alpha_flags = ImGuiColorEditFlags_None; } ImGui::SameLine();
     3975            if (ImGui::RadioButton("Alpha",  alpha_flags == ImGuiColorEditFlags_AlphaPreview))     { alpha_flags = ImGuiColorEditFlags_AlphaPreview; } ImGui::SameLine();
     3976            if (ImGui::RadioButton("Both",   alpha_flags == ImGuiColorEditFlags_AlphaPreviewHalf)) { alpha_flags = ImGuiColorEditFlags_AlphaPreviewHalf; } ImGui::SameLine();
     3977            HelpMarker(
     3978                "In the color list:\n"
     3979                "Left-click on colored square to open color picker,\n"
     3980                "Right-click to open edit options menu.");
     3981
     3982            ImGui::BeginChild("##colors", ImVec2(0, 0), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
     3983            ImGui::PushItemWidth(-160);
     3984            for (int i = 0; i < ImGuiCol_COUNT; i++)
     3985            {
     3986                const char* name = ImGui::GetStyleColorName(i);
     3987                if (!filter.PassFilter(name))
     3988                    continue;
     3989                ImGui::PushID(i);
     3990                ImGui::ColorEdit4("##color", (float*)&style.Colors[i], ImGuiColorEditFlags_AlphaBar | alpha_flags);
     3991                if (memcmp(&style.Colors[i], &ref->Colors[i], sizeof(ImVec4)) != 0)
     3992                {
     3993                    // Tips: in a real user application, you may want to merge and use an icon font into the main font,
     3994                    // so instead of "Save"/"Revert" you'd use icons!
     3995                    // Read the FAQ and docs/FONTS.md about using icon fonts. It's really easy and super convenient!
     3996                    ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Save")) { ref->Colors[i] = style.Colors[i]; }
     3997                    ImGui::SameLine(0.0f, style.ItemInnerSpacing.x); if (ImGui::Button("Revert")) { style.Colors[i] = ref->Colors[i]; }
     3998                }
     3999                ImGui::SameLine(0.0f, style.ItemInnerSpacing.x);
     4000                ImGui::TextUnformatted(name);
     4001                ImGui::PopID();
     4002            }
     4003            ImGui::PopItemWidth();
     4004            ImGui::EndChild();
     4005
     4006            ImGui::EndTabItem();
     4007        }
     4008
     4009        if (ImGui::BeginTabItem("Fonts"))
     4010        {
     4011            ImGuiIO& io = ImGui::GetIO();
     4012            ImFontAtlas* atlas = io.Fonts;
     4013            HelpMarker("Read FAQ and docs/FONTS.md for details on font loading.");
     4014            ImGui::PushItemWidth(120);
     4015            for (int i = 0; i < atlas->Fonts.Size; i++)
     4016            {
     4017                ImFont* font = atlas->Fonts[i];
     4018                ImGui::PushID(font);
     4019                NodeFont(font);
     4020                ImGui::PopID();
     4021            }
     4022            if (ImGui::TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
     4023            {
     4024                ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
     4025                ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
     4026                ImGui::Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0, 0), ImVec2(1, 1), tint_col, border_col);
     4027                ImGui::TreePop();
     4028            }
     4029
     4030            // Post-baking font scaling. Note that this is NOT the nice way of scaling fonts, read below.
     4031            // (we enforce hard clamping manually as by default DragFloat/SliderFloat allows CTRL+Click text to get out of bounds).
     4032            const float MIN_SCALE = 0.3f;
     4033            const float MAX_SCALE = 2.0f;
     4034            HelpMarker(
     4035                "Those are old settings provided for convenience.\n"
     4036                "However, the _correct_ way of scaling your UI is currently to reload your font at the designed size, "
     4037                "rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.\n"
     4038                "Using those settings here will give you poor quality results.");
     4039            static float window_scale = 1.0f;
     4040            if (ImGui::DragFloat("window scale", &window_scale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp)) // Scale only this window
     4041                ImGui::SetWindowFontScale(window_scale);
     4042            ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
     4043            ImGui::PopItemWidth();
     4044
     4045            ImGui::EndTabItem();
     4046        }
     4047
     4048        if (ImGui::BeginTabItem("Rendering"))
     4049        {
     4050            ImGui::Checkbox("Anti-aliased lines", &style.AntiAliasedLines);
     4051            ImGui::SameLine();
     4052            HelpMarker("When disabling anti-aliasing lines, you'll probably want to disable borders in your style as well.");
     4053
     4054            ImGui::Checkbox("Anti-aliased lines use texture", &style.AntiAliasedLinesUseTex);
     4055            ImGui::SameLine();
     4056            HelpMarker("Faster lines using texture data. Require back-end to render with bilinear filtering (not point/nearest filtering).");
     4057
     4058            ImGui::Checkbox("Anti-aliased fill", &style.AntiAliasedFill);
     4059            ImGui::PushItemWidth(100);
     4060            ImGui::DragFloat("Curve Tessellation Tolerance", &style.CurveTessellationTol, 0.02f, 0.10f, 10.0f, "%.2f");
     4061            if (style.CurveTessellationTol < 0.10f) style.CurveTessellationTol = 0.10f;
     4062
     4063            // When editing the "Circle Segment Max Error" value, draw a preview of its effect on auto-tessellated circles.
     4064            ImGui::DragFloat("Circle Segment Max Error", &style.CircleSegmentMaxError, 0.01f, 0.10f, 10.0f, "%.2f");
     4065            if (ImGui::IsItemActive())
     4066            {
     4067                ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
     4068                ImGui::BeginTooltip();
     4069                ImVec2 p = ImGui::GetCursorScreenPos();
     4070                ImDrawList* draw_list = ImGui::GetWindowDrawList();
     4071                float RAD_MIN = 10.0f, RAD_MAX = 80.0f;
     4072                float off_x = 10.0f;
     4073                for (int n = 0; n < 7; n++)
     4074                {
     4075                    const float rad = RAD_MIN + (RAD_MAX - RAD_MIN) * (float)n / (7.0f - 1.0f);
     4076                    draw_list->AddCircle(ImVec2(p.x + off_x + rad, p.y + RAD_MAX), rad, ImGui::GetColorU32(ImGuiCol_Text), 0);
     4077                    off_x += 10.0f + rad * 2.0f;
     4078                }
     4079                ImGui::Dummy(ImVec2(off_x, RAD_MAX * 2.0f));
     4080                ImGui::EndTooltip();
     4081            }
     4082            ImGui::SameLine();
     4083            HelpMarker("When drawing circle primitives with \"num_segments == 0\" tesselation will be calculated automatically.");
     4084
     4085            ImGui::DragFloat("Global Alpha", &style.Alpha, 0.005f, 0.20f, 1.0f, "%.2f"); // Not exposing zero here so user doesn't "lose" the UI (zero alpha clips all widgets). But application code could have a toggle to switch between zero and non-zero.
     4086            ImGui::PopItemWidth();
     4087
     4088            ImGui::EndTabItem();
     4089        }
     4090
     4091        ImGui::EndTabBar();
     4092    }
     4093
     4094    ImGui::PopItemWidth();
    23224095}
    23234096
    2324 // Demonstrate creating a fullscreen menu bar and populating it.
     4097//-----------------------------------------------------------------------------
     4098// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
     4099//-----------------------------------------------------------------------------
     4100// - ShowExampleAppMainMenuBar()
     4101// - ShowExampleMenuFile()
     4102//-----------------------------------------------------------------------------
     4103
     4104// Demonstrate creating a "main" fullscreen menu bar and populating it.
     4105// Note the difference between BeginMainMenuBar() and BeginMenuBar():
     4106// - BeginMenuBar() = menu-bar inside current window (which needs the ImGuiWindowFlags_MenuBar flag!)
     4107// - BeginMainMenuBar() = helper to create menu-bar-sized window at the top of the main viewport + call BeginMenuBar() into it.
    23254108static void ShowExampleAppMainMenuBar()
    23264109{
    2327    if (ImGui::BeginMainMenuBar())
    2328    {
    2329       if (ImGui::BeginMenu("File"))
    2330       {
    2331          ShowExampleMenuFile();
    2332          ImGui::EndMenu();
    2333       }
    2334       if (ImGui::BeginMenu("Edit"))
    2335       {
    2336          if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
    2337          if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {}  // Disabled item
    2338          ImGui::Separator();
    2339          if (ImGui::MenuItem("Cut", "CTRL+X")) {}
    2340          if (ImGui::MenuItem("Copy", "CTRL+C")) {}
    2341          if (ImGui::MenuItem("Paste", "CTRL+V")) {}
    2342          ImGui::EndMenu();
    2343       }
    2344       ImGui::EndMainMenuBar();
    2345    }
     4110    if (ImGui::BeginMainMenuBar())
     4111    {
     4112        if (ImGui::BeginMenu("File"))
     4113        {
     4114            ShowExampleMenuFile();
     4115            ImGui::EndMenu();
     4116        }
     4117        if (ImGui::BeginMenu("Edit"))
     4118        {
     4119            if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
     4120            if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {}  // Disabled item
     4121            ImGui::Separator();
     4122            if (ImGui::MenuItem("Cut", "CTRL+X")) {}
     4123            if (ImGui::MenuItem("Copy", "CTRL+C")) {}
     4124            if (ImGui::MenuItem("Paste", "CTRL+V")) {}
     4125            ImGui::EndMenu();
     4126        }
     4127        ImGui::EndMainMenuBar();
     4128    }
    23464129}
    23474130
     4131// Note that shortcuts are currently provided for display only
     4132// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
    23484133static void ShowExampleMenuFile()
    23494134{
    2350    ImGui::MenuItem("(dummy menu)", NULL, false, false);
    2351    if (ImGui::MenuItem("New")) {}
    2352    if (ImGui::MenuItem("Open", "Ctrl+O")) {}
    2353    if (ImGui::BeginMenu("Open Recent"))
    2354    {
    2355       ImGui::MenuItem("fish_hat.c");
    2356       ImGui::MenuItem("fish_hat.inl");
    2357       ImGui::MenuItem("fish_hat.h");
    2358       if (ImGui::BeginMenu("More.."))
    2359       {
    2360          ImGui::MenuItem("Hello");
    2361          ImGui::MenuItem("Sailor");
    2362          if (ImGui::BeginMenu("Recurse.."))
    2363          {
    2364             ShowExampleMenuFile();
     4135    ImGui::MenuItem("(demo menu)", NULL, false, false);
     4136    if (ImGui::MenuItem("New")) {}
     4137    if (ImGui::MenuItem("Open", "Ctrl+O")) {}
     4138    if (ImGui::BeginMenu("Open Recent"))
     4139    {
     4140        ImGui::MenuItem("fish_hat.c");
     4141        ImGui::MenuItem("fish_hat.inl");
     4142        ImGui::MenuItem("fish_hat.h");
     4143        if (ImGui::BeginMenu("More.."))
     4144        {
     4145            ImGui::MenuItem("Hello");
     4146            ImGui::MenuItem("Sailor");
     4147            if (ImGui::BeginMenu("Recurse.."))
     4148            {
     4149                ShowExampleMenuFile();
     4150                ImGui::EndMenu();
     4151            }
    23654152            ImGui::EndMenu();
    2366          }
    2367          ImGui::EndMenu();
    2368       }
    2369       ImGui::EndMenu();
    2370    }
    2371    if (ImGui::MenuItem("Save", "Ctrl+S")) {}
    2372    if (ImGui::MenuItem("Save As..")) {}
    2373    ImGui::Separator();
    2374    if (ImGui::BeginMenu("Options"))
    2375    {
    2376       static bool enabled = true;
    2377       ImGui::MenuItem("Enabled", "", &enabled);
    2378       ImGui::BeginChild("child", ImVec2(0, 60), true);
    2379       for (int i = 0; i < 10; i++)
    2380          ImGui::Text("Scrolling Text %d", i);
    2381       ImGui::EndChild();
    2382       static float f = 0.5f;
    2383       static int n = 0;
    2384       static bool b = true;
    2385       ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
    2386       ImGui::InputFloat("Input", &f, 0.1f);
    2387       ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
    2388       ImGui::Checkbox("Check", &b);
    2389       ImGui::EndMenu();
    2390    }
    2391    if (ImGui::BeginMenu("Colors"))
    2392    {
    2393       float sz = ImGui::GetTextLineHeight();
    2394       for (int i = 0; i < ImGuiCol_COUNT; i++)
    2395       {
    2396          const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
    2397          ImVec2 p = ImGui::GetCursorScreenPos();
    2398          ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
    2399          ImGui::Dummy(ImVec2(sz, sz));
    2400          ImGui::SameLine();
    2401          ImGui::MenuItem(name);
    2402       }
    2403       ImGui::EndMenu();
    2404    }
    2405    if (ImGui::BeginMenu("Disabled", false)) // Disabled
    2406    {
    2407       IM_ASSERT(0);
    2408    }
    2409    if (ImGui::MenuItem("Checked", NULL, true)) {}
    2410    if (ImGui::MenuItem("Quit", "Alt+F4")) {}
     4153        }
     4154        ImGui::EndMenu();
     4155    }
     4156    if (ImGui::MenuItem("Save", "Ctrl+S")) {}
     4157    if (ImGui::MenuItem("Save As..")) {}
     4158
     4159    ImGui::Separator();
     4160    if (ImGui::BeginMenu("Options"))
     4161    {
     4162        static bool enabled = true;
     4163        ImGui::MenuItem("Enabled", "", &enabled);
     4164        ImGui::BeginChild("child", ImVec2(0, 60), true);
     4165        for (int i = 0; i < 10; i++)
     4166            ImGui::Text("Scrolling Text %d", i);
     4167        ImGui::EndChild();
     4168        static float f = 0.5f;
     4169        static int n = 0;
     4170        ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
     4171        ImGui::InputFloat("Input", &f, 0.1f);
     4172        ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
     4173        ImGui::EndMenu();
     4174    }
     4175
     4176    if (ImGui::BeginMenu("Colors"))
     4177    {
     4178        float sz = ImGui::GetTextLineHeight();
     4179        for (int i = 0; i < ImGuiCol_COUNT; i++)
     4180        {
     4181            const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
     4182            ImVec2 p = ImGui::GetCursorScreenPos();
     4183            ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
     4184            ImGui::Dummy(ImVec2(sz, sz));
     4185            ImGui::SameLine();
     4186            ImGui::MenuItem(name);
     4187        }
     4188        ImGui::EndMenu();
     4189    }
     4190
     4191    // Here we demonstrate appending again to the "Options" menu (which we already created above)
     4192    // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
     4193    // In a real code-base using it would make senses to use this feature from very different code locations.
     4194    if (ImGui::BeginMenu("Options")) // <-- Append!
     4195    {
     4196        static bool b = true;
     4197        ImGui::Checkbox("SomeOption", &b);
     4198        ImGui::EndMenu();
     4199    }
     4200
     4201    if (ImGui::BeginMenu("Disabled", false)) // Disabled
     4202    {
     4203        IM_ASSERT(0);
     4204    }
     4205    if (ImGui::MenuItem("Checked", NULL, true)) {}
     4206    if (ImGui::MenuItem("Quit", "Alt+F4")) {}
    24114207}
    24124208
    2413 // Demonstrate creating a window which gets auto-resized according to its content.
    2414 static void ShowExampleAppAutoResize(bool* p_open)
    2415 {
    2416    if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
    2417    {
    2418       ImGui::End();
    2419       return;
    2420    }
    2421 
    2422    static int lines = 10;
    2423    ImGui::Text("Window will resize every-frame to the size of its content.\nNote that you probably don't want to query the window size to\noutput your content because that would create a feedback loop.");
    2424    ImGui::SliderInt("Number of lines", &lines, 1, 20);
    2425    for (int i = 0; i < lines; i++)
    2426       ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
    2427    ImGui::End();
    2428 }
    2429 
    2430 // Demonstrate creating a window with custom resize constraints.
    2431 static void ShowExampleAppConstrainedResize(bool* p_open)
    2432 {
    2433    struct CustomConstraints // Helper functions to demonstrate programmatic constraints
    2434    {
    2435       static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); }
    2436       static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); }
    2437    };
    2438 
    2439    static bool auto_resize = false;
    2440    static int type = 0;
    2441    static int display_lines = 10;
    2442    if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0), ImVec2(-1, FLT_MAX));      // Vertical only
    2443    if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1), ImVec2(FLT_MAX, -1));      // Horizontal only
    2444    if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
    2445    if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1), ImVec2(500, -1));          // Width 400-500
    2446    if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400), ImVec2(-1, 500));          // Height 400-500
    2447    if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square);          // Always Square
    2448    if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)100);// Fixed Step
    2449 
    2450    ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
    2451    if (ImGui::Begin("Example: Constrained Resize", p_open, flags))
    2452    {
    2453       const char* desc[] =
    2454       {
    2455          "Resize vertical only",
    2456          "Resize horizontal only",
    2457          "Width > 100, Height > 100",
    2458          "Width 400-500",
    2459          "Height 400-500",
    2460          "Custom: Always Square",
    2461          "Custom: Fixed Steps (100)",
    2462       };
    2463       if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
    2464       if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
    2465       if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
    2466       ImGui::PushItemWidth(200);
    2467       ImGui::Combo("Constraint", &type, desc, IM_ARRAYSIZE(desc));
    2468       ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
    2469       ImGui::PopItemWidth();
    2470       ImGui::Checkbox("Auto-resize", &auto_resize);
    2471       for (int i = 0; i < display_lines; i++)
    2472          ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
    2473    }
    2474    ImGui::End();
    2475 }
    2476 
    2477 // Demonstrate creating a simple static window with no decoration + a context-menu to choose which corner of the screen to use.
    2478 static void ShowExampleAppFixedOverlay(bool* p_open)
    2479 {
    2480    const float DISTANCE = 10.0f;
    2481    static int corner = 0;
    2482    ImVec2 window_pos = ImVec2((corner & 1) ? ImGui::GetIO().DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? ImGui::GetIO().DisplaySize.y - DISTANCE : DISTANCE);
    2483    ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
    2484    if (corner != -1)
    2485       ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
    2486    ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background
    2487    if (ImGui::Begin("Example: Fixed Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
    2488    {
    2489       ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
    2490       ImGui::Separator();
    2491       if (ImGui::IsMousePosValid())
    2492          ImGui::Text("Mouse Position: (%.1f,%.1f)", ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y);
    2493       else
    2494          ImGui::Text("Mouse Position: <invalid>");
    2495       if (ImGui::BeginPopupContextWindow())
    2496       {
    2497          if (ImGui::MenuItem("Custom", NULL, corner == -1)) corner = -1;
    2498          if (ImGui::MenuItem("Top-left", NULL, corner == 0)) corner = 0;
    2499          if (ImGui::MenuItem("Top-right", NULL, corner == 1)) corner = 1;
    2500          if (ImGui::MenuItem("Bottom-left", NULL, corner == 2)) corner = 2;
    2501          if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3;
    2502          if (p_open && ImGui::MenuItem("Close")) *p_open = false;
    2503          ImGui::EndPopup();
    2504       }
    2505       ImGui::End();
    2506    }
    2507 }
    2508 
    2509 // Demonstrate using "##" and "###" in identifiers to manipulate ID generation.
    2510 // This apply to regular items as well. Read FAQ section "How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs." for details.
    2511 static void ShowExampleAppWindowTitles(bool*)
    2512 {
    2513    // By default, Windows are uniquely identified by their title.
    2514    // You can use the "##" and "###" markers to manipulate the display/ID.
    2515 
    2516    // Using "##" to display same title but have unique identifier.
    2517    ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
    2518    ImGui::Begin("Same title as another window##1");
    2519    ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
    2520    ImGui::End();
    2521 
    2522    ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver);
    2523    ImGui::Begin("Same title as another window##2");
    2524    ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
    2525    ImGui::End();
    2526 
    2527    // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
    2528    char buf[128];
    2529    sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
    2530    ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver);
    2531    ImGui::Begin(buf);
    2532    ImGui::Text("This window has a changing title.");
    2533    ImGui::End();
    2534 }
    2535 
    2536 // Demonstrate using the low-level ImDrawList to draw custom shapes.
    2537 static void ShowExampleAppCustomRendering(bool* p_open)
    2538 {
    2539    ImGui::SetNextWindowSize(ImVec2(350, 560), ImGuiCond_FirstUseEver);
    2540    if (!ImGui::Begin("Example: Custom rendering", p_open))
    2541    {
    2542       ImGui::End();
    2543       return;
    2544    }
    2545 
    2546    // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of overloaded operators, etc.
    2547    // Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your types and ImVec2/ImVec4.
    2548    // ImGui defines overloaded operators but they are internal to imgui.cpp and not exposed outside (to avoid messing with your types)
    2549    // In this example we are not using the maths operators!
    2550    ImDrawList* draw_list = ImGui::GetWindowDrawList();
    2551 
    2552    // Primitives
    2553    ImGui::Text("Primitives");
    2554    static float sz = 36.0f;
    2555    static ImVec4 col = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
    2556    ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
    2557    ImGui::ColorEdit3("Color", &col.x);
    2558    {
    2559       const ImVec2 p = ImGui::GetCursorScreenPos();
    2560       const ImU32 col32 = ImColor(col);
    2561       float x = p.x + 4.0f, y = p.y + 4.0f, spacing = 8.0f;
    2562       for (int n = 0; n < 2; n++)
    2563       {
    2564          float thickness = (n == 0) ? 1.0f : 4.0f;
    2565          draw_list->AddCircle(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col32, 20, thickness); x += sz + spacing;
    2566          draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 0.0f, ImDrawCornerFlags_All, thickness); x += sz + spacing;
    2567          draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_All, thickness); x += sz + spacing;
    2568          draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight, thickness); x += sz + spacing;
    2569          draw_list->AddTriangle(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32, thickness); x += sz + spacing;
    2570          draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col32, thickness); x += sz + spacing;
    2571          draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, thickness); x += sz + spacing;
    2572          draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col32, thickness); x += spacing;
    2573          draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz * 1.3f, y + sz * 0.3f), ImVec2(x + sz - sz * 1.3f, y + sz - sz * 0.3f), ImVec2(x + sz, y + sz), col32, thickness);
    2574          x = p.x + 4;
    2575          y += sz + spacing;
    2576       }
    2577       draw_list->AddCircleFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col32, 32); x += sz + spacing;
    2578       draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32); x += sz + spacing;
    2579       draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f); x += sz + spacing;
    2580       draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col32, 10.0f, ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight); x += sz + spacing;
    2581       draw_list->AddTriangleFilled(ImVec2(x + sz * 0.5f, y), ImVec2(x + sz, y + sz - 0.5f), ImVec2(x, y + sz - 0.5f), col32); x += sz + spacing;
    2582       draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255));
    2583       ImGui::Dummy(ImVec2((sz + spacing) * 8, (sz + spacing) * 3));
    2584    }
    2585    ImGui::Separator();
    2586    {
    2587       static ImVector<ImVec2> points;
    2588       static bool adding_line = false;
    2589       ImGui::Text("Canvas example");
    2590       if (ImGui::Button("Clear")) points.clear();
    2591       if (points.Size >= 2) { ImGui::SameLine(); if (ImGui::Button("Undo")) { points.pop_back(); points.pop_back(); } }
    2592       ImGui::Text("Left-click and drag to add lines,\nRight-click to undo");
    2593 
    2594       // Here we are using InvisibleButton() as a convenience to 1) advance the cursor and 2) allows us to use IsItemHovered()
    2595       // However you can draw directly and poll mouse/keyboard by yourself. You can manipulate the cursor using GetCursorPos() and SetCursorPos().
    2596       // If you only use the ImDrawList API, you can notify the owner window of its extends by using SetCursorPos(max).
    2597       ImVec2 canvas_pos = ImGui::GetCursorScreenPos();            // ImDrawList API uses screen coordinates!
    2598       ImVec2 canvas_size = ImGui::GetContentRegionAvail();        // Resize canvas to what's available
    2599       if (canvas_size.x < 50.0f) canvas_size.x = 50.0f;
    2600       if (canvas_size.y < 50.0f) canvas_size.y = 50.0f;
    2601       draw_list->AddRectFilledMultiColor(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(50, 50, 50, 255), IM_COL32(50, 50, 60, 255), IM_COL32(60, 60, 70, 255), IM_COL32(50, 50, 60, 255));
    2602       draw_list->AddRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), IM_COL32(255, 255, 255, 255));
    2603 
    2604       bool adding_preview = false;
    2605       ImGui::InvisibleButton("canvas", canvas_size);
    2606       ImVec2 mouse_pos_in_canvas = ImVec2(ImGui::GetIO().MousePos.x - canvas_pos.x, ImGui::GetIO().MousePos.y - canvas_pos.y);
    2607       if (adding_line)
    2608       {
    2609          adding_preview = true;
    2610          points.push_back(mouse_pos_in_canvas);
    2611          if (!ImGui::IsMouseDown(0))
    2612             adding_line = adding_preview = false;
    2613       }
    2614       if (ImGui::IsItemHovered())
    2615       {
    2616          if (!adding_line && ImGui::IsMouseClicked(0))
    2617          {
    2618             points.push_back(mouse_pos_in_canvas);
    2619             adding_line = true;
    2620          }
    2621          if (ImGui::IsMouseClicked(1) && !points.empty())
    2622          {
    2623             adding_line = adding_preview = false;
    2624             points.pop_back();
    2625             points.pop_back();
    2626          }
    2627       }
    2628       draw_list->PushClipRect(canvas_pos, ImVec2(canvas_pos.x + canvas_size.x, canvas_pos.y + canvas_size.y), true);      // clip lines within the canvas (if we resize it, etc.)
    2629       for (int i = 0; i < points.Size - 1; i += 2)
    2630          draw_list->AddLine(ImVec2(canvas_pos.x + points[i].x, canvas_pos.y + points[i].y), ImVec2(canvas_pos.x + points[i + 1].x, canvas_pos.y + points[i + 1].y), IM_COL32(255, 255, 0, 255), 2.0f);
    2631       draw_list->PopClipRect();
    2632       if (adding_preview)
    2633          points.pop_back();
    2634    }
    2635    ImGui::End();
    2636 }
    2637 
    2638 // Demonstrating creating a simple console window, with scrolling, filtering, completion and history.
    2639 // For the console example, here we are using a more C++ like approach of declaring a class to hold the data and the functions.
     4209//-----------------------------------------------------------------------------
     4210// [SECTION] Example App: Debug Console / ShowExampleAppConsole()
     4211//-----------------------------------------------------------------------------
     4212
     4213// Demonstrate creating a simple console window, with scrolling, filtering, completion and history.
     4214// For the console example, we are using a more C++ like approach of declaring a class to hold both data and functions.
    26404215struct ExampleAppConsole
    26414216{
    2642    char                  InputBuf[256];
    2643    ImVector<char*>       Items;
    2644    bool                  ScrollToBottom;
    2645    ImVector<char*>       History;
    2646    int                   HistoryPos;    // -1: new line, 0..History.Size-1 browsing history.
    2647    ImVector<const char*> Commands;
    2648 
    2649    ExampleAppConsole()
    2650    {
    2651       ClearLog();
    2652       memset(InputBuf, 0, sizeof(InputBuf));
    2653       HistoryPos = -1;
    2654       Commands.push_back("HELP");
    2655       Commands.push_back("HISTORY");
    2656       Commands.push_back("CLEAR");
    2657       Commands.push_back("CLASSIFY");  // "classify" is here to provide an example of "C"+[tab] completing to "CL" and displaying matches.
    2658       AddLog("Welcome to ImGui!");
    2659    }
    2660    ~ExampleAppConsole()
    2661    {
    2662       ClearLog();
    2663       for (int i = 0; i < History.Size; i++)
    2664          free(History[i]);
    2665    }
    2666 
    2667    // Portable helpers
    2668    static int   Stricmp(const char* str1, const char* str2) { int d; while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; } return d; }
    2669    static int   Strnicmp(const char* str1, const char* str2, int n) { int d = 0; while (n > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; n--; } return d; }
    2670    static char* Strdup(const char *str) { size_t len = strlen(str) + 1; void* buff = malloc(len); return (char*)memcpy(buff, (const void*)str, len); }
    2671 
    2672    void    ClearLog()
    2673    {
    2674       for (int i = 0; i < Items.Size; i++)
    2675          free(Items[i]);
    2676       Items.clear();
    2677       ScrollToBottom = true;
    2678    }
    2679 
    2680    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
    2681    {
    2682       // FIXME-OPT
    2683       char buf[1024];
    2684       va_list args;
    2685       va_start(args, fmt);
    2686       vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
    2687       buf[IM_ARRAYSIZE(buf) - 1] = 0;
    2688       va_end(args);
    2689       Items.push_back(Strdup(buf));
    2690       ScrollToBottom = true;
    2691    }
    2692 
    2693    void    Draw(const char* title, bool* p_open)
    2694    {
    2695       ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
    2696       if (!ImGui::Begin(title, p_open))
    2697       {
    2698          ImGui::End();
    2699          return;
    2700       }
    2701 
    2702       // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar.
    2703       // Here we create a context menu only available from the title bar.
    2704       if (ImGui::BeginPopupContextItem())
    2705       {
    2706          if (ImGui::MenuItem("Close"))
    2707             *p_open = false;
    2708          ImGui::EndPopup();
    2709       }
    2710 
    2711       ImGui::TextWrapped("This example implements a console with basic coloring, completion and history. A more elaborate implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
    2712       ImGui::TextWrapped("Enter 'HELP' for help, press TAB to use text completion.");
    2713 
    2714       // TODO: display items starting from the bottom
    2715 
    2716       if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine();
    2717       if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine();
    2718       if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine();
    2719       bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine();
    2720       if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true;
    2721       //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
    2722 
    2723       ImGui::Separator();
    2724 
    2725       ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
    2726       static ImGuiTextFilter filter;
    2727       filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
    2728       ImGui::PopStyleVar();
    2729       ImGui::Separator();
    2730 
    2731       const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); // 1 separator, 1 input text
    2732       ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar); // Leave room for 1 separator + 1 InputText
    2733       if (ImGui::BeginPopupContextWindow())
    2734       {
    2735          if (ImGui::Selectable("Clear")) ClearLog();
    2736          ImGui::EndPopup();
    2737       }
    2738 
    2739       // Display every line as a separate entry so we can change their color or add custom widgets. If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
    2740       // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping to only process visible items.
    2741       // You can seek and display only the lines that are visible using the ImGuiListClipper helper, if your elements are evenly spaced and you have cheap random access to the elements.
    2742       // To use the clipper we could replace the 'for (int i = 0; i < Items.Size; i++)' loop with:
    2743       //     ImGuiListClipper clipper(Items.Size);
    2744       //     while (clipper.Step())
    2745       //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
    2746       // However take note that you can not use this code as is if a filter is active because it breaks the 'cheap random-access' property. We would need random-access on the post-filtered list.
    2747       // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices that passed the filtering test, recomputing this array when user changes the filter,
    2748       // and appending newly elements as they are inserted. This is left as a task to the user until we can manage to improve this example code!
    2749       // If your items are of variable size you may want to implement code similar to what ImGuiListClipper does. Or split your data into fixed height items to allow random-seeking into your list.
    2750       ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
    2751       if (copy_to_clipboard)
    2752          ImGui::LogToClipboard();
    2753       ImVec4 col_default_text = ImGui::GetStyleColorVec4(ImGuiCol_Text);
    2754       for (int i = 0; i < Items.Size; i++)
    2755       {
    2756          const char* item = Items[i];
    2757          if (!filter.PassFilter(item))
    2758             continue;
    2759          ImVec4 col = col_default_text;
    2760          if (strstr(item, "[error]")) col = ImColor(1.0f, 0.4f, 0.4f, 1.0f);
    2761          else if (strncmp(item, "# ", 2) == 0) col = ImColor(1.0f, 0.78f, 0.58f, 1.0f);
    2762          ImGui::PushStyleColor(ImGuiCol_Text, col);
    2763          ImGui::TextUnformatted(item);
    2764          ImGui::PopStyleColor();
    2765       }
    2766       if (copy_to_clipboard)
    2767          ImGui::LogFinish();
    2768       if (ScrollToBottom)
    2769          ImGui::SetScrollHere();
    2770       ScrollToBottom = false;
    2771       ImGui::PopStyleVar();
    2772       ImGui::EndChild();
    2773       ImGui::Separator();
    2774 
    2775       // Command-line
    2776       bool reclaim_focus = false;
    2777       if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory, &TextEditCallbackStub, (void*)this))
    2778       {
    2779          char* input_end = InputBuf + strlen(InputBuf);
    2780          while (input_end > InputBuf && input_end[-1] == ' ') { input_end--; } *input_end = 0;
    2781          if (InputBuf[0])
    2782             ExecCommand(InputBuf);
    2783          strcpy(InputBuf, "");
    2784          reclaim_focus = true;
    2785       }
    2786 
    2787       // Demonstrate keeping focus on the input box
    2788       ImGui::SetItemDefaultFocus();
    2789       if (reclaim_focus)
    2790          ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
    2791 
    2792       ImGui::End();
    2793    }
    2794 
    2795    void    ExecCommand(const char* command_line)
    2796    {
    2797       AddLog("# %s\n", command_line);
    2798 
    2799       // Insert into history. First find match and delete it so it can be pushed to the back. This isn't trying to be smart or optimal.
    2800       HistoryPos = -1;
    2801       for (int i = History.Size - 1; i >= 0; i--)
    2802          if (Stricmp(History[i], command_line) == 0)
    2803          {
     4217    char                  InputBuf[256];
     4218    ImVector<char*>       Items;
     4219    ImVector<const char*> Commands;
     4220    ImVector<char*>       History;
     4221    int                   HistoryPos;    // -1: new line, 0..History.Size-1 browsing history.
     4222    ImGuiTextFilter       Filter;
     4223    bool                  AutoScroll;
     4224    bool                  ScrollToBottom;
     4225
     4226    ExampleAppConsole()
     4227    {
     4228        ClearLog();
     4229        memset(InputBuf, 0, sizeof(InputBuf));
     4230        HistoryPos = -1;
     4231
     4232        // "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
     4233        Commands.push_back("HELP");
     4234        Commands.push_back("HISTORY");
     4235        Commands.push_back("CLEAR");
     4236        Commands.push_back("CLASSIFY");
     4237        AutoScroll = true;
     4238        ScrollToBottom = false;
     4239        AddLog("Welcome to Dear ImGui!");
     4240    }
     4241    ~ExampleAppConsole()
     4242    {
     4243        ClearLog();
     4244        for (int i = 0; i < History.Size; i++)
    28044245            free(History[i]);
    2805             History.erase(History.begin() + i);
    2806             break;
    2807          }
    2808       History.push_back(Strdup(command_line));
    2809 
    2810       // Process command
    2811       if (Stricmp(command_line, "CLEAR") == 0)
    2812       {
    2813          ClearLog();
    2814       }
    2815       else if (Stricmp(command_line, "HELP") == 0)
    2816       {
    2817          AddLog("Commands:");
    2818          for (int i = 0; i < Commands.Size; i++)
    2819             AddLog("- %s", Commands[i]);
    2820       }
    2821       else if (Stricmp(command_line, "HISTORY") == 0)
    2822       {
    2823          int first = History.Size - 10;
    2824          for (int i = first > 0 ? first : 0; i < History.Size; i++)
    2825             AddLog("%3d: %s\n", i, History[i]);
    2826       }
    2827       else
    2828       {
    2829          AddLog("Unknown command: '%s'\n", command_line);
    2830       }
    2831    }
    2832 
    2833    static int TextEditCallbackStub(ImGuiTextEditCallbackData* data) // In C++11 you are better off using lambdas for this sort of forwarding callbacks
    2834    {
    2835       ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
    2836       return console->TextEditCallback(data);
    2837    }
    2838 
    2839    int     TextEditCallback(ImGuiTextEditCallbackData* data)
    2840    {
    2841       //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
    2842       switch (data->EventFlag)
    2843       {
    2844       case ImGuiInputTextFlags_CallbackCompletion:
    2845       {
    2846          // Example of TEXT COMPLETION
    2847 
    2848          // Locate beginning of current word
    2849          const char* word_end = data->Buf + data->CursorPos;
    2850          const char* word_start = word_end;
    2851          while (word_start > data->Buf)
    2852          {
    2853             const char c = word_start[-1];
    2854             if (c == ' ' || c == '\t' || c == ',' || c == ';')
    2855                break;
    2856             word_start--;
    2857          }
    2858 
    2859          // Build a list of candidates
    2860          ImVector<const char*> candidates;
    2861          for (int i = 0; i < Commands.Size; i++)
    2862             if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
    2863                candidates.push_back(Commands[i]);
    2864 
    2865          if (candidates.Size == 0)
    2866          {
    2867             // No match
    2868             AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
    2869          }
    2870          else if (candidates.Size == 1)
    2871          {
    2872             // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing
    2873             data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
    2874             data->InsertChars(data->CursorPos, candidates[0]);
    2875             data->InsertChars(data->CursorPos, " ");
    2876          }
    2877          else
    2878          {
    2879             // Multiple matches. Complete as much as we can, so inputing "C" will complete to "CL" and display "CLEAR" and "CLASSIFY"
    2880             int match_len = (int)(word_end - word_start);
    2881             for (;;)
    2882             {
    2883                int c = 0;
    2884                bool all_candidates_matches = true;
    2885                for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
    2886                   if (i == 0)
    2887                      c = toupper(candidates[i][match_len]);
    2888                   else if (c == 0 || c != toupper(candidates[i][match_len]))
    2889                      all_candidates_matches = false;
    2890                if (!all_candidates_matches)
    2891                   break;
    2892                match_len++;
    2893             }
    2894 
    2895             if (match_len > 0)
    2896             {
    2897                data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
    2898                data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
    2899             }
    2900 
    2901             // List matches
    2902             AddLog("Possible matches:\n");
    2903             for (int i = 0; i < candidates.Size; i++)
    2904                AddLog("- %s\n", candidates[i]);
    2905          }
    2906 
    2907          break;
    2908       }
    2909       case ImGuiInputTextFlags_CallbackHistory:
    2910       {
    2911          // Example of HISTORY
    2912          const int prev_history_pos = HistoryPos;
    2913          if (data->EventKey == ImGuiKey_UpArrow)
    2914          {
    2915             if (HistoryPos == -1)
    2916                HistoryPos = History.Size - 1;
    2917             else if (HistoryPos > 0)
    2918                HistoryPos--;
    2919          }
    2920          else if (data->EventKey == ImGuiKey_DownArrow)
    2921          {
    2922             if (HistoryPos != -1)
    2923                if (++HistoryPos >= History.Size)
    2924                   HistoryPos = -1;
    2925          }
    2926 
    2927          // A better implementation would preserve the data on the current input line along with cursor position.
    2928          if (prev_history_pos != HistoryPos)
    2929          {
    2930             data->CursorPos = data->SelectionStart = data->SelectionEnd = data->BufTextLen = (int)snprintf(data->Buf, (size_t)data->BufSize, "%s", (HistoryPos >= 0) ? History[HistoryPos] : "");
    2931             data->BufDirty = true;
    2932          }
    2933       }
    2934       }
    2935       return 0;
    2936    }
     4246    }
     4247
     4248    // Portable helpers
     4249    static int   Stricmp(const char* s1, const char* s2)         { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
     4250    static int   Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; }
     4251    static char* Strdup(const char* s)                           { size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); }
     4252    static void  Strtrim(char* s)                                { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
     4253
     4254    void    ClearLog()
     4255    {
     4256        for (int i = 0; i < Items.Size; i++)
     4257            free(Items[i]);
     4258        Items.clear();
     4259    }
     4260
     4261    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
     4262    {
     4263        // FIXME-OPT
     4264        char buf[1024];
     4265        va_list args;
     4266        va_start(args, fmt);
     4267        vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
     4268        buf[IM_ARRAYSIZE(buf)-1] = 0;
     4269        va_end(args);
     4270        Items.push_back(Strdup(buf));
     4271    }
     4272
     4273    void    Draw(const char* title, bool* p_open)
     4274    {
     4275        ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
     4276        if (!ImGui::Begin(title, p_open))
     4277        {
     4278            ImGui::End();
     4279            return;
     4280        }
     4281
     4282        // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
     4283        // So e.g. IsItemHovered() will return true when hovering the title bar.
     4284        // Here we create a context menu only available from the title bar.
     4285        if (ImGui::BeginPopupContextItem())
     4286        {
     4287            if (ImGui::MenuItem("Close Console"))
     4288                *p_open = false;
     4289            ImGui::EndPopup();
     4290        }
     4291
     4292        ImGui::TextWrapped(
     4293            "This example implements a console with basic coloring, completion (TAB key) and history (Up/Down keys). A more elaborate "
     4294            "implementation may want to store entries along with extra data such as timestamp, emitter, etc.");
     4295        ImGui::TextWrapped("Enter 'HELP' for help.");
     4296
     4297        // TODO: display items starting from the bottom
     4298
     4299        if (ImGui::SmallButton("Add Debug Text"))  { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); }
     4300        ImGui::SameLine();
     4301        if (ImGui::SmallButton("Add Debug Error")) { AddLog("[error] something went wrong"); }
     4302        ImGui::SameLine();
     4303        if (ImGui::SmallButton("Clear"))           { ClearLog(); }
     4304        ImGui::SameLine();
     4305        bool copy_to_clipboard = ImGui::SmallButton("Copy");
     4306        //static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
     4307
     4308        ImGui::Separator();
     4309
     4310        // Options menu
     4311        if (ImGui::BeginPopup("Options"))
     4312        {
     4313            ImGui::Checkbox("Auto-scroll", &AutoScroll);
     4314            ImGui::EndPopup();
     4315        }
     4316
     4317        // Options, Filter
     4318        if (ImGui::Button("Options"))
     4319            ImGui::OpenPopup("Options");
     4320        ImGui::SameLine();
     4321        Filter.Draw("Filter (\"incl,-excl\") (\"error\")", 180);
     4322        ImGui::Separator();
     4323
     4324        // Reserve enough left-over height for 1 separator + 1 input text
     4325        const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
     4326        ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), false, ImGuiWindowFlags_HorizontalScrollbar);
     4327        if (ImGui::BeginPopupContextWindow())
     4328        {
     4329            if (ImGui::Selectable("Clear")) ClearLog();
     4330            ImGui::EndPopup();
     4331        }
     4332
     4333        // Display every line as a separate entry so we can change their color or add custom widgets.
     4334        // If you only want raw text you can use ImGui::TextUnformatted(log.begin(), log.end());
     4335        // NB- if you have thousands of entries this approach may be too inefficient and may require user-side clipping
     4336        // to only process visible items. The clipper will automatically measure the height of your first item and then
     4337        // "seek" to display only items in the visible area.
     4338        // To use the clipper we can replace your standard loop:
     4339        //      for (int i = 0; i < Items.Size; i++)
     4340        //   With:
     4341        //      ImGuiListClipper clipper;
     4342        //      clipper.Begin(Items.Size);
     4343        //      while (clipper.Step())
     4344        //         for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
     4345        // - That your items are evenly spaced (same height)
     4346        // - That you have cheap random access to your elements (you can access them given their index,
     4347        //   without processing all the ones before)
     4348        // You cannot this code as-is if a filter is active because it breaks the 'cheap random-access' property.
     4349        // We would need random-access on the post-filtered list.
     4350        // A typical application wanting coarse clipping and filtering may want to pre-compute an array of indices
     4351        // or offsets of items that passed the filtering test, recomputing this array when user changes the filter,
     4352        // and appending newly elements as they are inserted. This is left as a task to the user until we can manage
     4353        // to improve this example code!
     4354        // If your items are of variable height:
     4355        // - Split them into same height items would be simpler and facilitate random-seeking into your list.
     4356        // - Consider using manual call to IsRectVisible() and skipping extraneous decoration from your items.
     4357        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
     4358        if (copy_to_clipboard)
     4359            ImGui::LogToClipboard();
     4360        for (int i = 0; i < Items.Size; i++)
     4361        {
     4362            const char* item = Items[i];
     4363            if (!Filter.PassFilter(item))
     4364                continue;
     4365
     4366            // Normally you would store more information in your item than just a string.
     4367            // (e.g. make Items[] an array of structure, store color/type etc.)
     4368            ImVec4 color;
     4369            bool has_color = false;
     4370            if (strstr(item, "[error]"))          { color = ImVec4(1.0f, 0.4f, 0.4f, 1.0f); has_color = true; }
     4371            else if (strncmp(item, "# ", 2) == 0) { color = ImVec4(1.0f, 0.8f, 0.6f, 1.0f); has_color = true; }
     4372            if (has_color)
     4373                ImGui::PushStyleColor(ImGuiCol_Text, color);
     4374            ImGui::TextUnformatted(item);
     4375            if (has_color)
     4376                ImGui::PopStyleColor();
     4377        }
     4378        if (copy_to_clipboard)
     4379            ImGui::LogFinish();
     4380
     4381        if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
     4382            ImGui::SetScrollHereY(1.0f);
     4383        ScrollToBottom = false;
     4384
     4385        ImGui::PopStyleVar();
     4386        ImGui::EndChild();
     4387        ImGui::Separator();
     4388
     4389        // Command-line
     4390        bool reclaim_focus = false;
     4391        ImGuiInputTextFlags input_text_flags = ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory;
     4392        if (ImGui::InputText("Input", InputBuf, IM_ARRAYSIZE(InputBuf), input_text_flags, &TextEditCallbackStub, (void*)this))
     4393        {
     4394            char* s = InputBuf;
     4395            Strtrim(s);
     4396            if (s[0])
     4397                ExecCommand(s);
     4398            strcpy(s, "");
     4399            reclaim_focus = true;
     4400        }
     4401
     4402        // Auto-focus on window apparition
     4403        ImGui::SetItemDefaultFocus();
     4404        if (reclaim_focus)
     4405            ImGui::SetKeyboardFocusHere(-1); // Auto focus previous widget
     4406
     4407        ImGui::End();
     4408    }
     4409
     4410    void    ExecCommand(const char* command_line)
     4411    {
     4412        AddLog("# %s\n", command_line);
     4413
     4414        // Insert into history. First find match and delete it so it can be pushed to the back.
     4415        // This isn't trying to be smart or optimal.
     4416        HistoryPos = -1;
     4417        for (int i = History.Size - 1; i >= 0; i--)
     4418            if (Stricmp(History[i], command_line) == 0)
     4419            {
     4420                free(History[i]);
     4421                History.erase(History.begin() + i);
     4422                break;
     4423            }
     4424        History.push_back(Strdup(command_line));
     4425
     4426        // Process command
     4427        if (Stricmp(command_line, "CLEAR") == 0)
     4428        {
     4429            ClearLog();
     4430        }
     4431        else if (Stricmp(command_line, "HELP") == 0)
     4432        {
     4433            AddLog("Commands:");
     4434            for (int i = 0; i < Commands.Size; i++)
     4435                AddLog("- %s", Commands[i]);
     4436        }
     4437        else if (Stricmp(command_line, "HISTORY") == 0)
     4438        {
     4439            int first = History.Size - 10;
     4440            for (int i = first > 0 ? first : 0; i < History.Size; i++)
     4441                AddLog("%3d: %s\n", i, History[i]);
     4442        }
     4443        else
     4444        {
     4445            AddLog("Unknown command: '%s'\n", command_line);
     4446        }
     4447
     4448        // On command input, we scroll to bottom even if AutoScroll==false
     4449        ScrollToBottom = true;
     4450    }
     4451
     4452    // In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
     4453    static int TextEditCallbackStub(ImGuiInputTextCallbackData* data)
     4454    {
     4455        ExampleAppConsole* console = (ExampleAppConsole*)data->UserData;
     4456        return console->TextEditCallback(data);
     4457    }
     4458
     4459    int     TextEditCallback(ImGuiInputTextCallbackData* data)
     4460    {
     4461        //AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
     4462        switch (data->EventFlag)
     4463        {
     4464        case ImGuiInputTextFlags_CallbackCompletion:
     4465            {
     4466                // Example of TEXT COMPLETION
     4467
     4468                // Locate beginning of current word
     4469                const char* word_end = data->Buf + data->CursorPos;
     4470                const char* word_start = word_end;
     4471                while (word_start > data->Buf)
     4472                {
     4473                    const char c = word_start[-1];
     4474                    if (c == ' ' || c == '\t' || c == ',' || c == ';')
     4475                        break;
     4476                    word_start--;
     4477                }
     4478
     4479                // Build a list of candidates
     4480                ImVector<const char*> candidates;
     4481                for (int i = 0; i < Commands.Size; i++)
     4482                    if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
     4483                        candidates.push_back(Commands[i]);
     4484
     4485                if (candidates.Size == 0)
     4486                {
     4487                    // No match
     4488                    AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
     4489                }
     4490                else if (candidates.Size == 1)
     4491                {
     4492                    // Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
     4493                    data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
     4494                    data->InsertChars(data->CursorPos, candidates[0]);
     4495                    data->InsertChars(data->CursorPos, " ");
     4496                }
     4497                else
     4498                {
     4499                    // Multiple matches. Complete as much as we can..
     4500                    // So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
     4501                    int match_len = (int)(word_end - word_start);
     4502                    for (;;)
     4503                    {
     4504                        int c = 0;
     4505                        bool all_candidates_matches = true;
     4506                        for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
     4507                            if (i == 0)
     4508                                c = toupper(candidates[i][match_len]);
     4509                            else if (c == 0 || c != toupper(candidates[i][match_len]))
     4510                                all_candidates_matches = false;
     4511                        if (!all_candidates_matches)
     4512                            break;
     4513                        match_len++;
     4514                    }
     4515
     4516                    if (match_len > 0)
     4517                    {
     4518                        data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
     4519                        data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
     4520                    }
     4521
     4522                    // List matches
     4523                    AddLog("Possible matches:\n");
     4524                    for (int i = 0; i < candidates.Size; i++)
     4525                        AddLog("- %s\n", candidates[i]);
     4526                }
     4527
     4528                break;
     4529            }
     4530        case ImGuiInputTextFlags_CallbackHistory:
     4531            {
     4532                // Example of HISTORY
     4533                const int prev_history_pos = HistoryPos;
     4534                if (data->EventKey == ImGuiKey_UpArrow)
     4535                {
     4536                    if (HistoryPos == -1)
     4537                        HistoryPos = History.Size - 1;
     4538                    else if (HistoryPos > 0)
     4539                        HistoryPos--;
     4540                }
     4541                else if (data->EventKey == ImGuiKey_DownArrow)
     4542                {
     4543                    if (HistoryPos != -1)
     4544                        if (++HistoryPos >= History.Size)
     4545                            HistoryPos = -1;
     4546                }
     4547
     4548                // A better implementation would preserve the data on the current input line along with cursor position.
     4549                if (prev_history_pos != HistoryPos)
     4550                {
     4551                    const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
     4552                    data->DeleteChars(0, data->BufTextLen);
     4553                    data->InsertChars(0, history_str);
     4554                }
     4555            }
     4556        }
     4557        return 0;
     4558    }
    29374559};
    29384560
    29394561static void ShowExampleAppConsole(bool* p_open)
    29404562{
    2941    static ExampleAppConsole console;
    2942    console.Draw("Example: Console", p_open);
     4563    static ExampleAppConsole console;
     4564    console.Draw("Example: Console", p_open);
    29434565}
     4566
     4567//-----------------------------------------------------------------------------
     4568// [SECTION] Example App: Debug Log / ShowExampleAppLog()
     4569//-----------------------------------------------------------------------------
    29444570
    29454571// Usage:
     
    29494575struct ExampleAppLog
    29504576{
    2951    ImGuiTextBuffer     Buf;
    2952    ImGuiTextFilter     Filter;
    2953    ImVector<int>       LineOffsets;        // Index to lines offset
    2954    bool                ScrollToBottom;
    2955 
    2956    void    Clear() { Buf.clear(); LineOffsets.clear(); }
    2957 
    2958    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
    2959    {
    2960       int old_size = Buf.size();
    2961       va_list args;
    2962       va_start(args, fmt);
    2963       Buf.appendfv(fmt, args);
    2964       va_end(args);
    2965       for (int new_size = Buf.size(); old_size < new_size; old_size++)
    2966          if (Buf[old_size] == '\n')
    2967             LineOffsets.push_back(old_size);
    2968       ScrollToBottom = true;
    2969    }
    2970 
    2971    void    Draw(const char* title, bool* p_open = NULL)
    2972    {
    2973       ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
    2974       ImGui::Begin(title, p_open);
    2975       if (ImGui::Button("Clear")) Clear();
    2976       ImGui::SameLine();
    2977       bool copy = ImGui::Button("Copy");
    2978       ImGui::SameLine();
    2979       Filter.Draw("Filter", -100.0f);
    2980       ImGui::Separator();
    2981       ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
    2982       if (copy) ImGui::LogToClipboard();
    2983 
    2984       if (Filter.IsActive())
    2985       {
    2986          const char* buf_begin = Buf.begin();
    2987          const char* line = buf_begin;
    2988          for (int line_no = 0; line != NULL; line_no++)
    2989          {
    2990             const char* line_end = (line_no < LineOffsets.Size) ? buf_begin + LineOffsets[line_no] : NULL;
    2991             if (Filter.PassFilter(line, line_end))
    2992                ImGui::TextUnformatted(line, line_end);
    2993             line = line_end && line_end[1] ? line_end + 1 : NULL;
    2994          }
    2995       }
    2996       else
    2997       {
    2998          ImGui::TextUnformatted(Buf.begin());
    2999       }
    3000 
    3001       if (ScrollToBottom)
    3002          ImGui::SetScrollHere(1.0f);
    3003       ScrollToBottom = false;
    3004       ImGui::EndChild();
    3005       ImGui::End();
    3006    }
     4577    ImGuiTextBuffer     Buf;
     4578    ImGuiTextFilter     Filter;
     4579    ImVector<int>       LineOffsets; // Index to lines offset. We maintain this with AddLog() calls.
     4580    bool                AutoScroll;  // Keep scrolling if already at the bottom.
     4581
     4582    ExampleAppLog()
     4583    {
     4584        AutoScroll = true;
     4585        Clear();
     4586    }
     4587
     4588    void    Clear()
     4589    {
     4590        Buf.clear();
     4591        LineOffsets.clear();
     4592        LineOffsets.push_back(0);
     4593    }
     4594
     4595    void    AddLog(const char* fmt, ...) IM_FMTARGS(2)
     4596    {
     4597        int old_size = Buf.size();
     4598        va_list args;
     4599        va_start(args, fmt);
     4600        Buf.appendfv(fmt, args);
     4601        va_end(args);
     4602        for (int new_size = Buf.size(); old_size < new_size; old_size++)
     4603            if (Buf[old_size] == '\n')
     4604                LineOffsets.push_back(old_size + 1);
     4605    }
     4606
     4607    void    Draw(const char* title, bool* p_open = NULL)
     4608    {
     4609        if (!ImGui::Begin(title, p_open))
     4610        {
     4611            ImGui::End();
     4612            return;
     4613        }
     4614
     4615        // Options menu
     4616        if (ImGui::BeginPopup("Options"))
     4617        {
     4618            ImGui::Checkbox("Auto-scroll", &AutoScroll);
     4619            ImGui::EndPopup();
     4620        }
     4621
     4622        // Main window
     4623        if (ImGui::Button("Options"))
     4624            ImGui::OpenPopup("Options");
     4625        ImGui::SameLine();
     4626        bool clear = ImGui::Button("Clear");
     4627        ImGui::SameLine();
     4628        bool copy = ImGui::Button("Copy");
     4629        ImGui::SameLine();
     4630        Filter.Draw("Filter", -100.0f);
     4631
     4632        ImGui::Separator();
     4633        ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
     4634
     4635        if (clear)
     4636            Clear();
     4637        if (copy)
     4638            ImGui::LogToClipboard();
     4639
     4640        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
     4641        const char* buf = Buf.begin();
     4642        const char* buf_end = Buf.end();
     4643        if (Filter.IsActive())
     4644        {
     4645            // In this example we don't use the clipper when Filter is enabled.
     4646            // This is because we don't have a random access on the result on our filter.
     4647            // A real application processing logs with ten of thousands of entries may want to store the result of
     4648            // search/filter.. especially if the filtering function is not trivial (e.g. reg-exp).
     4649            for (int line_no = 0; line_no < LineOffsets.Size; line_no++)
     4650            {
     4651                const char* line_start = buf + LineOffsets[line_no];
     4652                const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
     4653                if (Filter.PassFilter(line_start, line_end))
     4654                    ImGui::TextUnformatted(line_start, line_end);
     4655            }
     4656        }
     4657        else
     4658        {
     4659            // The simplest and easy way to display the entire buffer:
     4660            //   ImGui::TextUnformatted(buf_begin, buf_end);
     4661            // And it'll just work. TextUnformatted() has specialization for large blob of text and will fast-forward
     4662            // to skip non-visible lines. Here we instead demonstrate using the clipper to only process lines that are
     4663            // within the visible area.
     4664            // If you have tens of thousands of items and their processing cost is non-negligible, coarse clipping them
     4665            // on your side is recommended. Using ImGuiListClipper requires
     4666            // - A) random access into your data
     4667            // - B) items all being the  same height,
     4668            // both of which we can handle since we an array pointing to the beginning of each line of text.
     4669            // When using the filter (in the block of code above) we don't have random access into the data to display
     4670            // anymore, which is why we don't use the clipper. Storing or skimming through the search result would make
     4671            // it possible (and would be recommended if you want to search through tens of thousands of entries).
     4672            ImGuiListClipper clipper;
     4673            clipper.Begin(LineOffsets.Size);
     4674            while (clipper.Step())
     4675            {
     4676                for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
     4677                {
     4678                    const char* line_start = buf + LineOffsets[line_no];
     4679                    const char* line_end = (line_no + 1 < LineOffsets.Size) ? (buf + LineOffsets[line_no + 1] - 1) : buf_end;
     4680                    ImGui::TextUnformatted(line_start, line_end);
     4681                }
     4682            }
     4683            clipper.End();
     4684        }
     4685        ImGui::PopStyleVar();
     4686
     4687        if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
     4688            ImGui::SetScrollHereY(1.0f);
     4689
     4690        ImGui::EndChild();
     4691        ImGui::End();
     4692    }
    30074693};
    30084694
     
    30104696static void ShowExampleAppLog(bool* p_open)
    30114697{
    3012    static ExampleAppLog log;
    3013 
    3014    // Demo: add random items (unless Ctrl is held)
    3015    static float last_time = -1.0f;
    3016    float time = ImGui::GetTime();
    3017    if (time - last_time >= 0.20f && !ImGui::GetIO().KeyCtrl)
    3018    {
    3019       const char* random_words[] = { "system", "info", "warning", "error", "fatal", "notice", "log" };
    3020       log.AddLog("[%s] Hello, time is %.1f, frame count is %d\n", random_words[rand() % IM_ARRAYSIZE(random_words)], time, ImGui::GetFrameCount());
    3021       last_time = time;
    3022    }
    3023 
    3024    log.Draw("Example: Log", p_open);
     4698    static ExampleAppLog log;
     4699
     4700    // For the demo: add a debug button _BEFORE_ the normal log window contents
     4701    // We take advantage of a rarely used feature: multiple calls to Begin()/End() are appending to the _same_ window.
     4702    // Most of the contents of the window will be added by the log.Draw() call.
     4703    ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
     4704    ImGui::Begin("Example: Log", p_open);
     4705    if (ImGui::SmallButton("[Debug] Add 5 entries"))
     4706    {
     4707        static int counter = 0;
     4708        const char* categories[3] = { "info", "warn", "error" };
     4709        const char* words[] = { "Bumfuzzled", "Cattywampus", "Snickersnee", "Abibliophobia", "Absquatulate", "Nincompoop", "Pauciloquent" };
     4710        for (int n = 0; n < 5; n++)
     4711        {
     4712            const char* category = categories[counter % IM_ARRAYSIZE(categories)];
     4713            const char* word = words[counter % IM_ARRAYSIZE(words)];
     4714            log.AddLog("[%05d] [%s] Hello, current time is %.1f, here's a word: '%s'\n",
     4715                ImGui::GetFrameCount(), category, ImGui::GetTime(), word);
     4716            counter++;
     4717        }
     4718    }
     4719    ImGui::End();
     4720
     4721    // Actually call in the regular Log helper (which will Begin() into the same window as we just did)
     4722    log.Draw("Example: Log", p_open);
    30254723}
     4724
     4725//-----------------------------------------------------------------------------
     4726// [SECTION] Example App: Simple Layout / ShowExampleAppLayout()
     4727//-----------------------------------------------------------------------------
    30264728
    30274729// Demonstrate create a window with multiple child windows.
    30284730static void ShowExampleAppLayout(bool* p_open)
    30294731{
    3030    ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
    3031    if (ImGui::Begin("Example: Layout", p_open, ImGuiWindowFlags_MenuBar))
    3032    {
    3033       if (ImGui::BeginMenuBar())
    3034       {
    3035          if (ImGui::BeginMenu("File"))
    3036          {
    3037             if (ImGui::MenuItem("Close")) *p_open = false;
    3038             ImGui::EndMenu();
    3039          }
    3040          ImGui::EndMenuBar();
    3041       }
    3042 
    3043       // left
    3044       static int selected = 0;
    3045       ImGui::BeginChild("left pane", ImVec2(150, 0), true);
    3046       for (int i = 0; i < 100; i++)
    3047       {
    3048          char label[128];
    3049          sprintf(label, "MyObject %d", i);
    3050          if (ImGui::Selectable(label, selected == i))
    3051             selected = i;
    3052       }
    3053       ImGui::EndChild();
    3054       ImGui::SameLine();
    3055 
    3056       // right
    3057       ImGui::BeginGroup();
    3058       ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
    3059       ImGui::Text("MyObject: %d", selected);
    3060       ImGui::Separator();
    3061       ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
    3062       ImGui::EndChild();
    3063       if (ImGui::Button("Revert")) {}
    3064       ImGui::SameLine();
    3065       if (ImGui::Button("Save")) {}
    3066       ImGui::EndGroup();
    3067    }
    3068    ImGui::End();
     4732    ImGui::SetNextWindowSize(ImVec2(500, 440), ImGuiCond_FirstUseEver);
     4733    if (ImGui::Begin("Example: Simple layout", p_open, ImGuiWindowFlags_MenuBar))
     4734    {
     4735        if (ImGui::BeginMenuBar())
     4736        {
     4737            if (ImGui::BeginMenu("File"))
     4738            {
     4739                if (ImGui::MenuItem("Close")) *p_open = false;
     4740                ImGui::EndMenu();
     4741            }
     4742            ImGui::EndMenuBar();
     4743        }
     4744
     4745        // Left
     4746        static int selected = 0;
     4747        {
     4748            ImGui::BeginChild("left pane", ImVec2(150, 0), true);
     4749            for (int i = 0; i < 100; i++)
     4750            {
     4751                char label[128];
     4752                sprintf(label, "MyObject %d", i);
     4753                if (ImGui::Selectable(label, selected == i))
     4754                    selected = i;
     4755            }
     4756            ImGui::EndChild();
     4757        }
     4758        ImGui::SameLine();
     4759
     4760        // Right
     4761        {
     4762            ImGui::BeginGroup();
     4763            ImGui::BeginChild("item view", ImVec2(0, -ImGui::GetFrameHeightWithSpacing())); // Leave room for 1 line below us
     4764            ImGui::Text("MyObject: %d", selected);
     4765            ImGui::Separator();
     4766            if (ImGui::BeginTabBar("##Tabs", ImGuiTabBarFlags_None))
     4767            {
     4768                if (ImGui::BeginTabItem("Description"))
     4769                {
     4770                    ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ");
     4771                    ImGui::EndTabItem();
     4772                }
     4773                if (ImGui::BeginTabItem("Details"))
     4774                {
     4775                    ImGui::Text("ID: 0123456789");
     4776                    ImGui::EndTabItem();
     4777                }
     4778                ImGui::EndTabBar();
     4779            }
     4780            ImGui::EndChild();
     4781            if (ImGui::Button("Revert")) {}
     4782            ImGui::SameLine();
     4783            if (ImGui::Button("Save")) {}
     4784            ImGui::EndGroup();
     4785        }
     4786    }
     4787    ImGui::End();
     4788}
     4789
     4790//-----------------------------------------------------------------------------
     4791// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
     4792//-----------------------------------------------------------------------------
     4793
     4794static void ShowPlaceholderObject(const char* prefix, int uid)
     4795{
     4796    // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
     4797    ImGui::PushID(uid);
     4798
     4799    // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high.
     4800    ImGui::AlignTextToFramePadding();
     4801    bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid);
     4802    ImGui::NextColumn();
     4803    ImGui::AlignTextToFramePadding();
     4804    ImGui::Text("my sailor is rich");
     4805    ImGui::NextColumn();
     4806    if (node_open)
     4807    {
     4808        static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f };
     4809        for (int i = 0; i < 8; i++)
     4810        {
     4811            ImGui::PushID(i); // Use field index as identifier.
     4812            if (i < 2)
     4813            {
     4814                ShowPlaceholderObject("Child", 424242);
     4815            }
     4816            else
     4817            {
     4818                // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well)
     4819                ImGui::AlignTextToFramePadding();
     4820                ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet;
     4821                ImGui::TreeNodeEx("Field", flags, "Field_%d", i);
     4822                ImGui::NextColumn();
     4823                ImGui::SetNextItemWidth(-1);
     4824                if (i >= 5)
     4825                    ImGui::InputFloat("##value", &placeholder_members[i], 1.0f);
     4826                else
     4827                    ImGui::DragFloat("##value", &placeholder_members[i], 0.01f);
     4828                ImGui::NextColumn();
     4829            }
     4830            ImGui::PopID();
     4831        }
     4832        ImGui::TreePop();
     4833    }
     4834    ImGui::PopID();
    30694835}
    30704836
     
    30724838static void ShowExampleAppPropertyEditor(bool* p_open)
    30734839{
    3074    ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
    3075    if (!ImGui::Begin("Example: Property editor", p_open))
    3076    {
    3077       ImGui::End();
    3078       return;
    3079    }
    3080 
    3081    ShowHelpMarker("This example shows how you may implement a property editor using two columns.\nAll objects/fields data are dummies here.\nRemember that in many simple cases, you can use ImGui::SameLine(xxx) to position\nyour cursor horizontally instead of using the Columns() API.");
    3082 
    3083    ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
    3084    ImGui::Columns(2);
    3085    ImGui::Separator();
    3086 
    3087    struct funcs
    3088    {
    3089       static void ShowDummyObject(const char* prefix, int uid)
    3090       {
    3091          ImGui::PushID(uid);                      // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
    3092          ImGui::AlignTextToFramePadding();  // Text and Tree nodes are less high than regular widgets, here we add vertical spacing to make the tree lines equal high.
    3093          bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid);
    3094          ImGui::NextColumn();
    3095          ImGui::AlignTextToFramePadding();
    3096          ImGui::Text("my sailor is rich");
    3097          ImGui::NextColumn();
    3098          if (node_open)
    3099          {
    3100             static float dummy_members[8] = { 0.0f,0.0f,1.0f,3.1416f,100.0f,999.0f };
    3101             for (int i = 0; i < 8; i++)
    3102             {
    3103                ImGui::PushID(i); // Use field index as identifier.
    3104                if (i < 2)
    3105                {
    3106                   ShowDummyObject("Child", 424242);
    3107                }
    3108                else
    3109                {
    3110                   ImGui::AlignTextToFramePadding();
    3111                   // Here we use a Selectable (instead of Text) to highlight on hover
    3112                   //ImGui::Text("Field_%d", i);
    3113                   char label[32];
    3114                   sprintf(label, "Field_%d", i);
    3115                   ImGui::Bullet();
    3116                   ImGui::Selectable(label);
    3117                   ImGui::NextColumn();
    3118                   ImGui::PushItemWidth(-1);
    3119                   if (i >= 5)
    3120                      ImGui::InputFloat("##value", &dummy_members[i], 1.0f);
    3121                   else
    3122                      ImGui::DragFloat("##value", &dummy_members[i], 0.01f);
    3123                   ImGui::PopItemWidth();
    3124                   ImGui::NextColumn();
    3125                }
    3126                ImGui::PopID();
    3127             }
    3128             ImGui::TreePop();
    3129          }
    3130          ImGui::PopID();
    3131       }
    3132    };
    3133 
    3134    // Iterate dummy objects with dummy members (all the same data)
    3135    for (int obj_i = 0; obj_i < 3; obj_i++)
    3136       funcs::ShowDummyObject("Object", obj_i);
    3137 
    3138    ImGui::Columns(1);
    3139    ImGui::Separator();
    3140    ImGui::PopStyleVar();
    3141    ImGui::End();
     4840    ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
     4841    if (!ImGui::Begin("Example: Property editor", p_open))
     4842    {
     4843        ImGui::End();
     4844        return;
     4845    }
     4846
     4847    HelpMarker(
     4848        "This example shows how you may implement a property editor using two columns.\n"
     4849        "All objects/fields data are dummies here.\n"
     4850        "Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n"
     4851        "your cursor horizontally instead of using the Columns() API.");
     4852
     4853    ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
     4854    ImGui::Columns(2);
     4855    ImGui::Separator();
     4856
     4857    // Iterate placeholder objects (all the same data)
     4858    for (int obj_i = 0; obj_i < 3; obj_i++)
     4859        ShowPlaceholderObject("Object", obj_i);
     4860
     4861    ImGui::Columns(1);
     4862    ImGui::Separator();
     4863    ImGui::PopStyleVar();
     4864    ImGui::End();
    31424865}
     4866
     4867//-----------------------------------------------------------------------------
     4868// [SECTION] Example App: Long Text / ShowExampleAppLongText()
     4869//-----------------------------------------------------------------------------
    31434870
    31444871// Demonstrate/test rendering huge amount of text, and the incidence of clipping.
    31454872static void ShowExampleAppLongText(bool* p_open)
    31464873{
    3147    ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
    3148    if (!ImGui::Begin("Example: Long text display", p_open))
    3149    {
    3150       ImGui::End();
    3151       return;
    3152    }
    3153 
    3154    static int test_type = 0;
    3155    static ImGuiTextBuffer log;
    3156    static int lines = 0;
    3157    ImGui::Text("Printing unusually long amount of text.");
    3158    ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0");
    3159    ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
    3160    if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
    3161    ImGui::SameLine();
    3162    if (ImGui::Button("Add 1000 lines"))
    3163    {
    3164       for (int i = 0; i < 1000; i++)
    3165          log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
    3166       lines += 1000;
    3167    }
    3168    ImGui::BeginChild("Log");
    3169    switch (test_type)
    3170    {
    3171    case 0:
    3172       // Single call to TextUnformatted() with a big buffer
    3173       ImGui::TextUnformatted(log.begin(), log.end());
    3174       break;
    3175    case 1:
    3176    {
    3177       // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
    3178       ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
    3179       ImGuiListClipper clipper(lines);
    3180       while (clipper.Step())
    3181          for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
     4874    ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
     4875    if (!ImGui::Begin("Example: Long text display", p_open))
     4876    {
     4877        ImGui::End();
     4878        return;
     4879    }
     4880
     4881    static int test_type = 0;
     4882    static ImGuiTextBuffer log;
     4883    static int lines = 0;
     4884    ImGui::Text("Printing unusually long amount of text.");
     4885    ImGui::Combo("Test type", &test_type,
     4886        "Single call to TextUnformatted()\0"
     4887        "Multiple calls to Text(), clipped\0"
     4888        "Multiple calls to Text(), not clipped (slow)\0");
     4889    ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
     4890    if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
     4891    ImGui::SameLine();
     4892    if (ImGui::Button("Add 1000 lines"))
     4893    {
     4894        for (int i = 0; i < 1000; i++)
     4895            log.appendf("%i The quick brown fox jumps over the lazy dog\n", lines + i);
     4896        lines += 1000;
     4897    }
     4898    ImGui::BeginChild("Log");
     4899    switch (test_type)
     4900    {
     4901    case 0:
     4902        // Single call to TextUnformatted() with a big buffer
     4903        ImGui::TextUnformatted(log.begin(), log.end());
     4904        break;
     4905    case 1:
     4906        {
     4907            // Multiple calls to Text(), manually coarsely clipped - demonstrate how to use the ImGuiListClipper helper.
     4908            ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
     4909            ImGuiListClipper clipper;
     4910            clipper.Begin(lines);
     4911            while (clipper.Step())
     4912                for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
     4913                    ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
     4914            ImGui::PopStyleVar();
     4915            break;
     4916        }
     4917    case 2:
     4918        // Multiple calls to Text(), not clipped (slow)
     4919        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
     4920        for (int i = 0; i < lines; i++)
    31824921            ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
    3183       ImGui::PopStyleVar();
    3184       break;
    3185    }
    3186    case 2:
    3187       // Multiple calls to Text(), not clipped (slow)
    3188       ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
    3189       for (int i = 0; i < lines; i++)
    3190          ImGui::Text("%i The quick brown fox jumps over the lazy dog", i);
    3191       ImGui::PopStyleVar();
    3192       break;
    3193    }
    3194    ImGui::EndChild();
    3195    ImGui::End();
     4922        ImGui::PopStyleVar();
     4923        break;
     4924    }
     4925    ImGui::EndChild();
     4926    ImGui::End();
     4927}
     4928
     4929//-----------------------------------------------------------------------------
     4930// [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize()
     4931//-----------------------------------------------------------------------------
     4932
     4933// Demonstrate creating a window which gets auto-resized according to its content.
     4934static void ShowExampleAppAutoResize(bool* p_open)
     4935{
     4936    if (!ImGui::Begin("Example: Auto-resizing window", p_open, ImGuiWindowFlags_AlwaysAutoResize))
     4937    {
     4938        ImGui::End();
     4939        return;
     4940    }
     4941
     4942    static int lines = 10;
     4943    ImGui::TextUnformatted(
     4944        "Window will resize every-frame to the size of its content.\n"
     4945        "Note that you probably don't want to query the window size to\n"
     4946        "output your content because that would create a feedback loop.");
     4947    ImGui::SliderInt("Number of lines", &lines, 1, 20);
     4948    for (int i = 0; i < lines; i++)
     4949        ImGui::Text("%*sThis is line %d", i * 4, "", i); // Pad with space to extend size horizontally
     4950    ImGui::End();
     4951}
     4952
     4953//-----------------------------------------------------------------------------
     4954// [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize()
     4955//-----------------------------------------------------------------------------
     4956
     4957// Demonstrate creating a window with custom resize constraints.
     4958static void ShowExampleAppConstrainedResize(bool* p_open)
     4959{
     4960    struct CustomConstraints
     4961    {
     4962        // Helper functions to demonstrate programmatic constraints
     4963        static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = IM_MAX(data->DesiredSize.x, data->DesiredSize.y); }
     4964        static void Step(ImGuiSizeCallbackData* data)   { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); }
     4965    };
     4966
     4967    const char* test_desc[] =
     4968    {
     4969        "Resize vertical only",
     4970        "Resize horizontal only",
     4971        "Width > 100, Height > 100",
     4972        "Width 400-500",
     4973        "Height 400-500",
     4974        "Custom: Always Square",
     4975        "Custom: Fixed Steps (100)",
     4976    };
     4977
     4978    static bool auto_resize = false;
     4979    static int type = 0;
     4980    static int display_lines = 10;
     4981    if (type == 0) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 0),    ImVec2(-1, FLT_MAX));      // Vertical only
     4982    if (type == 1) ImGui::SetNextWindowSizeConstraints(ImVec2(0, -1),    ImVec2(FLT_MAX, -1));      // Horizontal only
     4983    if (type == 2) ImGui::SetNextWindowSizeConstraints(ImVec2(100, 100), ImVec2(FLT_MAX, FLT_MAX)); // Width > 100, Height > 100
     4984    if (type == 3) ImGui::SetNextWindowSizeConstraints(ImVec2(400, -1),  ImVec2(500, -1));          // Width 400-500
     4985    if (type == 4) ImGui::SetNextWindowSizeConstraints(ImVec2(-1, 400),  ImVec2(-1, 500));          // Height 400-500
     4986    if (type == 5) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Square);                     // Always Square
     4987    if (type == 6) ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0),     ImVec2(FLT_MAX, FLT_MAX), CustomConstraints::Step, (void*)(intptr_t)100); // Fixed Step
     4988
     4989    ImGuiWindowFlags flags = auto_resize ? ImGuiWindowFlags_AlwaysAutoResize : 0;
     4990    if (ImGui::Begin("Example: Constrained Resize", p_open, flags))
     4991    {
     4992        if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
     4993        if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
     4994        if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
     4995        ImGui::SetNextItemWidth(200);
     4996        ImGui::Combo("Constraint", &type, test_desc, IM_ARRAYSIZE(test_desc));
     4997        ImGui::SetNextItemWidth(200);
     4998        ImGui::DragInt("Lines", &display_lines, 0.2f, 1, 100);
     4999        ImGui::Checkbox("Auto-resize", &auto_resize);
     5000        for (int i = 0; i < display_lines; i++)
     5001            ImGui::Text("%*sHello, sailor! Making this line long enough for the example.", i * 4, "");
     5002    }
     5003    ImGui::End();
     5004}
     5005
     5006//-----------------------------------------------------------------------------
     5007// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay()
     5008//-----------------------------------------------------------------------------
     5009
     5010// Demonstrate creating a simple static window with no decoration
     5011// + a context-menu to choose which corner of the screen to use.
     5012static void ShowExampleAppSimpleOverlay(bool* p_open)
     5013{
     5014    const float DISTANCE = 10.0f;
     5015    static int corner = 0;
     5016    ImGuiIO& io = ImGui::GetIO();
     5017    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
     5018    if (corner != -1)
     5019    {
     5020        window_flags |= ImGuiWindowFlags_NoMove;
     5021        ImVec2 window_pos = ImVec2((corner & 1) ? io.DisplaySize.x - DISTANCE : DISTANCE, (corner & 2) ? io.DisplaySize.y - DISTANCE : DISTANCE);
     5022        ImVec2 window_pos_pivot = ImVec2((corner & 1) ? 1.0f : 0.0f, (corner & 2) ? 1.0f : 0.0f);
     5023        ImGui::SetNextWindowPos(window_pos, ImGuiCond_Always, window_pos_pivot);
     5024    }
     5025    ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
     5026    if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
     5027    {
     5028        ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
     5029        ImGui::Separator();
     5030        if (ImGui::IsMousePosValid())
     5031            ImGui::Text("Mouse Position: (%.1f,%.1f)", io.MousePos.x, io.MousePos.y);
     5032        else
     5033            ImGui::Text("Mouse Position: <invalid>");
     5034        if (ImGui::BeginPopupContextWindow())
     5035        {
     5036            if (ImGui::MenuItem("Custom",       NULL, corner == -1)) corner = -1;
     5037            if (ImGui::MenuItem("Top-left",     NULL, corner == 0)) corner = 0;
     5038            if (ImGui::MenuItem("Top-right",    NULL, corner == 1)) corner = 1;
     5039            if (ImGui::MenuItem("Bottom-left",  NULL, corner == 2)) corner = 2;
     5040            if (ImGui::MenuItem("Bottom-right", NULL, corner == 3)) corner = 3;
     5041            if (p_open && ImGui::MenuItem("Close")) *p_open = false;
     5042            ImGui::EndPopup();
     5043        }
     5044    }
     5045    ImGui::End();
     5046}
     5047
     5048//-----------------------------------------------------------------------------
     5049// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
     5050//-----------------------------------------------------------------------------
     5051
     5052// Demonstrate using "##" and "###" in identifiers to manipulate ID generation.
     5053// This apply to all regular items as well.
     5054// Read FAQ section "How can I have multiple widgets with the same label?" for details.
     5055static void ShowExampleAppWindowTitles(bool*)
     5056{
     5057    // By default, Windows are uniquely identified by their title.
     5058    // You can use the "##" and "###" markers to manipulate the display/ID.
     5059
     5060    // Using "##" to display same title but have unique identifier.
     5061    ImGui::SetNextWindowPos(ImVec2(100, 100), ImGuiCond_FirstUseEver);
     5062    ImGui::Begin("Same title as another window##1");
     5063    ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
     5064    ImGui::End();
     5065
     5066    ImGui::SetNextWindowPos(ImVec2(100, 200), ImGuiCond_FirstUseEver);
     5067    ImGui::Begin("Same title as another window##2");
     5068    ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
     5069    ImGui::End();
     5070
     5071    // Using "###" to display a changing title but keep a static identifier "AnimatedTitle"
     5072    char buf[128];
     5073    sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
     5074    ImGui::SetNextWindowPos(ImVec2(100, 300), ImGuiCond_FirstUseEver);
     5075    ImGui::Begin(buf);
     5076    ImGui::Text("This window has a changing title.");
     5077    ImGui::End();
     5078}
     5079
     5080//-----------------------------------------------------------------------------
     5081// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
     5082//-----------------------------------------------------------------------------
     5083
     5084// Demonstrate using the low-level ImDrawList to draw custom shapes.
     5085static void ShowExampleAppCustomRendering(bool* p_open)
     5086{
     5087    if (!ImGui::Begin("Example: Custom rendering", p_open))
     5088    {
     5089        ImGui::End();
     5090        return;
     5091    }
     5092
     5093    // Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
     5094    // overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
     5095    // types and ImVec2/ImVec4. Dear ImGui defines overloaded operators but they are internal to imgui.cpp and not
     5096    // exposed outside (to avoid messing with your types) In this example we are not using the maths operators!
     5097
     5098    if (ImGui::BeginTabBar("##TabBar"))
     5099    {
     5100        if (ImGui::BeginTabItem("Primitives"))
     5101        {
     5102            ImGui::PushItemWidth(-ImGui::GetFontSize() * 10);
     5103            ImDrawList* draw_list = ImGui::GetWindowDrawList();
     5104
     5105            // Draw gradients
     5106            // (note that those are currently exacerbating our sRGB/Linear issues)
     5107            // Calling ImGui::GetColorU32() multiplies the given colors by the current Style Alpha, but you may pass the IM_COL32() directly as well..
     5108            ImGui::Text("Gradients");
     5109            ImVec2 gradient_size = ImVec2(ImGui::CalcItemWidth(), ImGui::GetFrameHeight());
     5110            {
     5111                ImVec2 p0 = ImGui::GetCursorScreenPos();
     5112                ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
     5113                ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 0, 0, 255));
     5114                ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 255, 255, 255));
     5115                draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
     5116                ImGui::InvisibleButton("##gradient1", gradient_size);
     5117            }
     5118            {
     5119                ImVec2 p0 = ImGui::GetCursorScreenPos();
     5120                ImVec2 p1 = ImVec2(p0.x + gradient_size.x, p0.y + gradient_size.y);
     5121                ImU32 col_a = ImGui::GetColorU32(IM_COL32(0, 255, 0, 255));
     5122                ImU32 col_b = ImGui::GetColorU32(IM_COL32(255, 0, 0, 255));
     5123                draw_list->AddRectFilledMultiColor(p0, p1, col_a, col_b, col_b, col_a);
     5124                ImGui::InvisibleButton("##gradient2", gradient_size);
     5125            }
     5126
     5127            // Draw a bunch of primitives
     5128            ImGui::Text("All primitives");
     5129            static float sz = 36.0f;
     5130            static float thickness = 3.0f;
     5131            static int ngon_sides = 6;
     5132            static bool circle_segments_override = false;
     5133            static int circle_segments_override_v = 12;
     5134            static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
     5135            ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
     5136            ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
     5137            ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
     5138            ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
     5139            ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
     5140            if (ImGui::SliderInt("Circle segments", &circle_segments_override_v, 3, 40))
     5141                circle_segments_override = true;
     5142            ImGui::ColorEdit4("Color", &colf.x);
     5143
     5144            const ImVec2 p = ImGui::GetCursorScreenPos();
     5145            const ImU32 col = ImColor(colf);
     5146            const float spacing = 10.0f;
     5147            const ImDrawCornerFlags corners_none = 0;
     5148            const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All;
     5149            const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight;
     5150            const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
     5151            float x = p.x + 4.0f;
     5152            float y = p.y + 4.0f;
     5153            for (int n = 0; n < 2; n++)
     5154            {
     5155                // First line uses a thickness of 1.0f, second line uses the configurable thickness
     5156                float th = (n == 0) ? 1.0f : thickness;
     5157                draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th);                 x += sz + spacing;  // N-gon
     5158                draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th);          x += sz + spacing;  // Circle
     5159                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f,  corners_none, th);             x += sz + spacing;  // Square
     5160                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th);              x += sz + spacing;  // Square with all rounded corners
     5161                draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th);            x += sz + spacing;  // Square with two rounded corners
     5162                draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing;  // Triangle
     5163                //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle
     5164                draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th);                                       x += sz + spacing;  // Horizontal line (note: drawing a filled rectangle will be faster!)
     5165                draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th);                                       x += spacing;       // Vertical line (note: drawing a filled rectangle will be faster!)
     5166                draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th);                                  x += sz + spacing;  // Diagonal line
     5167                draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col, th);
     5168                x = p.x + 4;
     5169                y += sz + spacing;
     5170            }
     5171            draw_list->AddNgonFilled(ImVec2(x + sz * 0.5f, y + sz * 0.5f), sz*0.5f, col, ngon_sides);               x += sz + spacing;  // N-gon
     5172            draw_list->AddCircleFilled(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments);            x += sz + spacing;  // Circle
     5173            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col);                                    x += sz + spacing;  // Square
     5174            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f);                             x += sz + spacing;  // Square with all rounded corners
     5175            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br);              x += sz + spacing;  // Square with two rounded corners
     5176            draw_list->AddTriangleFilled(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col);  x += sz + spacing;  // Triangle
     5177            //draw_list->AddTriangleFilled(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col); x += sz*0.4f + spacing; // Thin triangle
     5178            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + sz, y + thickness), col);                             x += sz + spacing;  // Horizontal line (faster than AddLine, but only handle integer thickness)
     5179            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + thickness, y + sz), col);                             x += spacing * 2.0f;// Vertical line (faster than AddLine, but only handle integer thickness)
     5180            draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + 1, y + 1), col);                                      x += sz;            // Pixel (faster than AddLine)
     5181            draw_list->AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + sz, y + sz), IM_COL32(0, 0, 0, 255), IM_COL32(255, 0, 0, 255), IM_COL32(255, 255, 0, 255), IM_COL32(0, 255, 0, 255));
     5182
     5183            ImGui::Dummy(ImVec2((sz + spacing) * 8.8f, (sz + spacing) * 3.0f));
     5184            ImGui::PopItemWidth();
     5185            ImGui::EndTabItem();
     5186        }
     5187
     5188        if (ImGui::BeginTabItem("Canvas"))
     5189        {
     5190            static ImVector<ImVec2> points;
     5191            static ImVec2 scrolling(0.0f, 0.0f);
     5192            static bool opt_enable_grid = true;
     5193            static bool opt_enable_context_menu = true;
     5194            static bool adding_line = false;
     5195
     5196            ImGui::Checkbox("Enable grid", &opt_enable_grid);
     5197            ImGui::Checkbox("Enable context menu", &opt_enable_context_menu);
     5198            ImGui::Text("Mouse Left: drag to add lines,\nMouse Right: drag to scroll, click for context menu.");
     5199
     5200            // Typically you would use a BeginChild()/EndChild() pair to benefit from a clipping region + own scrolling.
     5201            // Here we demonstrate that this can be replaced by simple offsetting + custom drawing + PushClipRect/PopClipRect() calls.
     5202            // To use a child window instead we could use, e.g:
     5203            //      ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));      // Disable padding
     5204            //      ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255));  // Set a background color
     5205            //      ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_NoMove);
     5206            //      ImGui::PopStyleColor();
     5207            //      ImGui::PopStyleVar();
     5208            //      [...]
     5209            //      ImGui::EndChild();
     5210
     5211            // Using InvisibleButton() as a convenience 1) it will advance the layout cursor and 2) allows us to use IsItemHovered()/IsItemActive()
     5212            ImVec2 canvas_p0 = ImGui::GetCursorScreenPos();      // ImDrawList API uses screen coordinates!
     5213            ImVec2 canvas_sz = ImGui::GetContentRegionAvail();   // Resize canvas to what's available
     5214            if (canvas_sz.x < 50.0f) canvas_sz.x = 50.0f;
     5215            if (canvas_sz.y < 50.0f) canvas_sz.y = 50.0f;
     5216            ImVec2 canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y);
     5217
     5218            // Draw border and background color
     5219            ImGuiIO& io = ImGui::GetIO();
     5220            ImDrawList* draw_list = ImGui::GetWindowDrawList();
     5221            draw_list->AddRectFilled(canvas_p0, canvas_p1, IM_COL32(50, 50, 50, 255));
     5222            draw_list->AddRect(canvas_p0, canvas_p1, IM_COL32(255, 255, 255, 255));
     5223
     5224            // This will catch our interactions
     5225            ImGui::InvisibleButton("canvas", canvas_sz, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight);
     5226            const bool is_hovered = ImGui::IsItemHovered(); // Hovered
     5227            const bool is_active = ImGui::IsItemActive();   // Held
     5228            const ImVec2 origin(canvas_p0.x + scrolling.x, canvas_p0.y + scrolling.y); // Lock scrolled origin
     5229            const ImVec2 mouse_pos_in_canvas(io.MousePos.x - origin.x, io.MousePos.y - origin.y);
     5230
     5231            // Add first and second point
     5232            if (is_hovered && !adding_line && ImGui::IsMouseClicked(ImGuiMouseButton_Left))
     5233            {
     5234                points.push_back(mouse_pos_in_canvas);
     5235                points.push_back(mouse_pos_in_canvas);
     5236                adding_line = true;
     5237            }
     5238            if (adding_line)
     5239            {
     5240                points.back() = mouse_pos_in_canvas;
     5241                if (!ImGui::IsMouseDown(ImGuiMouseButton_Left))
     5242                    adding_line = false;
     5243            }
     5244
     5245            // Pan (we use a zero mouse threshold when there's no context menu)
     5246            // You may decide to make that threshold dynamic based on whether the mouse is hovering something etc.
     5247            const float mouse_threshold_for_pan = opt_enable_context_menu ? -1.0f : 0.0f;
     5248            if (is_active && ImGui::IsMouseDragging(ImGuiMouseButton_Right, mouse_threshold_for_pan))
     5249            {
     5250                scrolling.x += io.MouseDelta.x;
     5251                scrolling.y += io.MouseDelta.y;
     5252            }
     5253
     5254            // Context menu (under default mouse threshold)
     5255            ImVec2 drag_delta = ImGui::GetMouseDragDelta(ImGuiMouseButton_Right);
     5256            if (opt_enable_context_menu && ImGui::IsMouseReleased(ImGuiMouseButton_Right) && drag_delta.x == 0.0f && drag_delta.y == 0.0f)
     5257                ImGui::OpenPopupOnItemClick("context");
     5258            if (ImGui::BeginPopup("context"))
     5259            {
     5260                if (adding_line)
     5261                    points.resize(points.size() - 2);
     5262                adding_line = false;
     5263                if (ImGui::MenuItem("Remove one", NULL, false, points.Size > 0)) { points.resize(points.size() - 2); }
     5264                if (ImGui::MenuItem("Remove all", NULL, false, points.Size > 0)) { points.clear(); }
     5265                ImGui::EndPopup();
     5266            }
     5267
     5268            // Draw grid + all lines in the canvas
     5269            draw_list->PushClipRect(canvas_p0, canvas_p1, true);
     5270            if (opt_enable_grid)
     5271            {
     5272                const float GRID_STEP = 64.0f;
     5273                for (float x = fmodf(scrolling.x, GRID_STEP); x < canvas_sz.x; x += GRID_STEP)
     5274                    draw_list->AddLine(ImVec2(canvas_p0.x + x, canvas_p0.y), ImVec2(canvas_p0.x + x, canvas_p1.y), IM_COL32(200, 200, 200, 40));
     5275                for (float y = fmodf(scrolling.y, GRID_STEP); y < canvas_sz.y; y += GRID_STEP)
     5276                    draw_list->AddLine(ImVec2(canvas_p0.x, canvas_p0.y + y), ImVec2(canvas_p1.x, canvas_p0.y + y), IM_COL32(200, 200, 200, 40));
     5277            }
     5278            for (int n = 0; n < points.Size; n += 2)
     5279                draw_list->AddLine(ImVec2(origin.x + points[n].x, origin.y + points[n].y), ImVec2(origin.x + points[n + 1].x, origin.y + points[n + 1].y), IM_COL32(255, 255, 0, 255), 2.0f);
     5280            draw_list->PopClipRect();
     5281
     5282            ImGui::EndTabItem();
     5283        }
     5284
     5285        if (ImGui::BeginTabItem("BG/FG draw lists"))
     5286        {
     5287            static bool draw_bg = true;
     5288            static bool draw_fg = true;
     5289            ImGui::Checkbox("Draw in Background draw list", &draw_bg);
     5290            ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
     5291            ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
     5292            ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
     5293            ImVec2 window_pos = ImGui::GetWindowPos();
     5294            ImVec2 window_size = ImGui::GetWindowSize();
     5295            ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
     5296            if (draw_bg)
     5297                ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 0, 10 + 4);
     5298            if (draw_fg)
     5299                ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 0, 10);
     5300            ImGui::EndTabItem();
     5301        }
     5302
     5303        ImGui::EndTabBar();
     5304    }
     5305
     5306    ImGui::End();
     5307}
     5308
     5309//-----------------------------------------------------------------------------
     5310// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
     5311//-----------------------------------------------------------------------------
     5312
     5313// Simplified structure to mimic a Document model
     5314struct MyDocument
     5315{
     5316    const char* Name;       // Document title
     5317    bool        Open;       // Set when open (we keep an array of all available documents to simplify demo code!)
     5318    bool        OpenPrev;   // Copy of Open from last update.
     5319    bool        Dirty;      // Set when the document has been modified
     5320    bool        WantClose;  // Set when the document
     5321    ImVec4      Color;      // An arbitrary variable associated to the document
     5322
     5323    MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f))
     5324    {
     5325        Name = name;
     5326        Open = OpenPrev = open;
     5327        Dirty = false;
     5328        WantClose = false;
     5329        Color = color;
     5330    }
     5331    void DoOpen()       { Open = true; }
     5332    void DoQueueClose() { WantClose = true; }
     5333    void DoForceClose() { Open = false; Dirty = false; }
     5334    void DoSave()       { Dirty = false; }
     5335
     5336    // Display placeholder contents for the Document
     5337    static void DisplayContents(MyDocument* doc)
     5338    {
     5339        ImGui::PushID(doc);
     5340        ImGui::Text("Document \"%s\"", doc->Name);
     5341        ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
     5342        ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
     5343        ImGui::PopStyleColor();
     5344        if (ImGui::Button("Modify", ImVec2(100, 0)))
     5345            doc->Dirty = true;
     5346        ImGui::SameLine();
     5347        if (ImGui::Button("Save", ImVec2(100, 0)))
     5348            doc->DoSave();
     5349        ImGui::ColorEdit3("color", &doc->Color.x);  // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
     5350        ImGui::PopID();
     5351    }
     5352
     5353    // Display context menu for the Document
     5354    static void DisplayContextMenu(MyDocument* doc)
     5355    {
     5356        if (!ImGui::BeginPopupContextItem())
     5357            return;
     5358
     5359        char buf[256];
     5360        sprintf(buf, "Save %s", doc->Name);
     5361        if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open))
     5362            doc->DoSave();
     5363        if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open))
     5364            doc->DoQueueClose();
     5365        ImGui::EndPopup();
     5366    }
     5367};
     5368
     5369struct ExampleAppDocuments
     5370{
     5371    ImVector<MyDocument> Documents;
     5372
     5373    ExampleAppDocuments()
     5374    {
     5375        Documents.push_back(MyDocument("Lettuce",             true,  ImVec4(0.4f, 0.8f, 0.4f, 1.0f)));
     5376        Documents.push_back(MyDocument("Eggplant",            true,  ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
     5377        Documents.push_back(MyDocument("Carrot",              true,  ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
     5378        Documents.push_back(MyDocument("Tomato",              false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
     5379        Documents.push_back(MyDocument("A Rather Long Title", false));
     5380        Documents.push_back(MyDocument("Some Document",       false));
     5381    }
     5382};
     5383
     5384// [Optional] Notify the system of Tabs/Windows closure that happened outside the regular tab interface.
     5385// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo,
     5386// as opposed to clicking on the regular tab closing button) and stops being submitted, it will take a frame for
     5387// the tab bar to notice its absence. During this frame there will be a gap in the tab bar, and if the tab that has
     5388// disappeared was the selected one, the tab bar will report no selected tab during the frame. This will effectively
     5389// give the impression of a flicker for one frame.
     5390// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
     5391// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
     5392static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
     5393{
     5394    for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
     5395    {
     5396        MyDocument* doc = &app.Documents[doc_n];
     5397        if (!doc->Open && doc->OpenPrev)
     5398            ImGui::SetTabItemClosed(doc->Name);
     5399        doc->OpenPrev = doc->Open;
     5400    }
     5401}
     5402
     5403void ShowExampleAppDocuments(bool* p_open)
     5404{
     5405    static ExampleAppDocuments app;
     5406
     5407    // Options
     5408    static bool opt_reorderable = true;
     5409    static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
     5410
     5411    bool window_contents_visible = ImGui::Begin("Example: Documents", p_open, ImGuiWindowFlags_MenuBar);
     5412    if (!window_contents_visible)
     5413    {
     5414        ImGui::End();
     5415        return;
     5416    }
     5417
     5418    // Menu
     5419    if (ImGui::BeginMenuBar())
     5420    {
     5421        if (ImGui::BeginMenu("File"))
     5422        {
     5423            int open_count = 0;
     5424            for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
     5425                open_count += app.Documents[doc_n].Open ? 1 : 0;
     5426
     5427            if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
     5428            {
     5429                for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
     5430                {
     5431                    MyDocument* doc = &app.Documents[doc_n];
     5432                    if (!doc->Open)
     5433                        if (ImGui::MenuItem(doc->Name))
     5434                            doc->DoOpen();
     5435                }
     5436                ImGui::EndMenu();
     5437            }
     5438            if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
     5439                for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
     5440                    app.Documents[doc_n].DoQueueClose();
     5441            if (ImGui::MenuItem("Exit", "Alt+F4")) {}
     5442            ImGui::EndMenu();
     5443        }
     5444        ImGui::EndMenuBar();
     5445    }
     5446
     5447    // [Debug] List documents with one checkbox for each
     5448    for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
     5449    {
     5450        MyDocument* doc = &app.Documents[doc_n];
     5451        if (doc_n > 0)
     5452            ImGui::SameLine();
     5453        ImGui::PushID(doc);
     5454        if (ImGui::Checkbox(doc->Name, &doc->Open))
     5455            if (!doc->Open)
     5456                doc->DoForceClose();
     5457        ImGui::PopID();
     5458    }
     5459
     5460    ImGui::Separator();
     5461
     5462    // Submit Tab Bar and Tabs
     5463    {
     5464        ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
     5465        if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
     5466        {
     5467            if (opt_reorderable)
     5468                NotifyOfDocumentsClosedElsewhere(app);
     5469
     5470            // [DEBUG] Stress tests
     5471            //if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1;            // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
     5472            //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name);  // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
     5473
     5474            // Submit Tabs
     5475            for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
     5476            {
     5477                MyDocument* doc = &app.Documents[doc_n];
     5478                if (!doc->Open)
     5479                    continue;
     5480
     5481                ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
     5482                bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags);
     5483
     5484                // Cancel attempt to close when unsaved add to save queue so we can display a popup.
     5485                if (!doc->Open && doc->Dirty)
     5486                {
     5487                    doc->Open = true;
     5488                    doc->DoQueueClose();
     5489                }
     5490
     5491                MyDocument::DisplayContextMenu(doc);
     5492                if (visible)
     5493                {
     5494                    MyDocument::DisplayContents(doc);
     5495                    ImGui::EndTabItem();
     5496                }
     5497            }
     5498
     5499            ImGui::EndTabBar();
     5500        }
     5501    }
     5502
     5503    // Update closing queue
     5504    static ImVector<MyDocument*> close_queue;
     5505    if (close_queue.empty())
     5506    {
     5507        // Close queue is locked once we started a popup
     5508        for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
     5509        {
     5510            MyDocument* doc = &app.Documents[doc_n];
     5511            if (doc->WantClose)
     5512            {
     5513                doc->WantClose = false;
     5514                close_queue.push_back(doc);
     5515            }
     5516        }
     5517    }
     5518
     5519    // Display closing confirmation UI
     5520    if (!close_queue.empty())
     5521    {
     5522        int close_queue_unsaved_documents = 0;
     5523        for (int n = 0; n < close_queue.Size; n++)
     5524            if (close_queue[n]->Dirty)
     5525                close_queue_unsaved_documents++;
     5526
     5527        if (close_queue_unsaved_documents == 0)
     5528        {
     5529            // Close documents when all are unsaved
     5530            for (int n = 0; n < close_queue.Size; n++)
     5531                close_queue[n]->DoForceClose();
     5532            close_queue.clear();
     5533        }
     5534        else
     5535        {
     5536            if (!ImGui::IsPopupOpen("Save?"))
     5537                ImGui::OpenPopup("Save?");
     5538            if (ImGui::BeginPopupModal("Save?"))
     5539            {
     5540                ImGui::Text("Save change to the following items?");
     5541                ImGui::SetNextItemWidth(-1.0f);
     5542                if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6))
     5543                {
     5544                    for (int n = 0; n < close_queue.Size; n++)
     5545                        if (close_queue[n]->Dirty)
     5546                            ImGui::Text("%s", close_queue[n]->Name);
     5547                    ImGui::ListBoxFooter();
     5548                }
     5549
     5550                if (ImGui::Button("Yes", ImVec2(80, 0)))
     5551                {
     5552                    for (int n = 0; n < close_queue.Size; n++)
     5553                    {
     5554                        if (close_queue[n]->Dirty)
     5555                            close_queue[n]->DoSave();
     5556                        close_queue[n]->DoForceClose();
     5557                    }
     5558                    close_queue.clear();
     5559                    ImGui::CloseCurrentPopup();
     5560                }
     5561                ImGui::SameLine();
     5562                if (ImGui::Button("No", ImVec2(80, 0)))
     5563                {
     5564                    for (int n = 0; n < close_queue.Size; n++)
     5565                        close_queue[n]->DoForceClose();
     5566                    close_queue.clear();
     5567                    ImGui::CloseCurrentPopup();
     5568                }
     5569                ImGui::SameLine();
     5570                if (ImGui::Button("Cancel", ImVec2(80, 0)))
     5571                {
     5572                    close_queue.clear();
     5573                    ImGui::CloseCurrentPopup();
     5574                }
     5575                ImGui::EndPopup();
     5576            }
     5577        }
     5578    }
     5579
     5580    ImGui::End();
    31965581}
    31975582
     
    31995584#else
    32005585
     5586void ImGui::ShowAboutWindow(bool*) {}
    32015587void ImGui::ShowDemoWindow(bool*) {}
    32025588void ImGui::ShowUserGuide() {}
     
    32045590
    32055591#endif
     5592
     5593#endif // #ifndef IMGUI_DISABLE
  • IMGUI/imgui_draw.cpp

    r78c3045 re66fd66  
    1 // dear imgui, v1.61 WIP
     1// dear imgui, v1.79
    22// (drawing and font code)
    33
    4 // Contains implementation for
    5 // - Default styles
    6 // - ImDrawList
    7 // - ImDrawData
    8 // - ImFontAtlas
    9 // - ImFont
    10 // - Default font data
     4/*
     5
     6Index of this file:
     7
     8// [SECTION] STB libraries implementation
     9// [SECTION] Style functions
     10// [SECTION] ImDrawList
     11// [SECTION] ImDrawListSplitter
     12// [SECTION] ImDrawData
     13// [SECTION] Helpers ShadeVertsXXX functions
     14// [SECTION] ImFontConfig
     15// [SECTION] ImFontAtlas
     16// [SECTION] ImFontAtlas glyph ranges helpers
     17// [SECTION] ImFontGlyphRangesBuilder
     18// [SECTION] ImFont
     19// [SECTION] ImGui Internal Render Helpers
     20// [SECTION] Decompression code
     21// [SECTION] Default font data (ProggyClean.ttf)
     22
     23*/
    1124
    1225#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
     
    1528
    1629#include "imgui.h"
     30#ifndef IMGUI_DISABLE
     31
     32#ifndef IMGUI_DEFINE_MATH_OPERATORS
    1733#define IMGUI_DEFINE_MATH_OPERATORS
     34#endif
    1835#include "imgui_internal.h"
    1936
    2037#include <stdio.h>      // vsnprintf, sscanf, printf
    2138#if !defined(alloca)
    22 #ifdef _WIN32
     39#if defined(__GLIBC__) || defined(__sun) || defined(__APPLE__) || defined(__NEWLIB__)
     40#include <alloca.h>     // alloca (glibc uses <alloca.h>. Note that Cygwin may have _WIN32 defined, so the order matters here)
     41#elif defined(_WIN32)
    2342#include <malloc.h>     // alloca
    2443#if !defined(alloca)
    2544#define alloca _alloca  // for clang with MS Codegen
    2645#endif
    27 #elif defined(__GLIBC__) || defined(__sun)
    28 #include <alloca.h>     // alloca
    2946#else
    3047#include <stdlib.h>     // alloca
     
    3249#endif
    3350
     51// Visual Studio warnings
    3452#ifdef _MSC_VER
     53#pragma warning (disable: 4127) // condition expression is constant
    3554#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
    3655#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
    3756#endif
    3857
    39 #ifdef __clang__
    40 #pragma clang diagnostic ignored "-Wold-style-cast"         // warning : use of old-style cast                              // yes, they are more terse.
    41 #pragma clang diagnostic ignored "-Wfloat-equal"            // warning : comparing floating point with == or != is unsafe   // storing and comparing against same constants ok.
    42 #pragma clang diagnostic ignored "-Wglobal-constructors"    // warning : declaration requires a global destructor           // similar to above, not sure what the exact difference it.
    43 #pragma clang diagnostic ignored "-Wsign-conversion"        // warning : implicit conversion changes signedness             //
    44 #if __has_warning("-Wcomma")
    45 #pragma clang diagnostic ignored "-Wcomma"                  // warning : possible misuse of comma operator here             //
     58// Clang/GCC warnings with -Weverything
     59#if defined(__clang__)
     60#if __has_warning("-Wunknown-warning-option")
     61#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!
    4662#endif
    47 #if __has_warning("-Wreserved-id-macro")
    48 #pragma clang diagnostic ignored "-Wreserved-id-macro"      // warning : macro name is a reserved identifier                //
    49 #endif
    50 #if __has_warning("-Wdouble-promotion")
    51 #pragma clang diagnostic ignored "-Wdouble-promotion"       // warning: implicit conversion from 'float' to 'double' when passing argument to function
    52 #endif
     63#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
     64#pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                            // yes, they are more terse.
     65#pragma clang diagnostic ignored "-Wfloat-equal"                    // warning: comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
     66#pragma clang diagnostic ignored "-Wglobal-constructors"            // warning: declaration requires a global destructor         // similar to above, not sure what the exact difference is.
     67#pragma clang diagnostic ignored "-Wsign-conversion"                // warning: implicit conversion changes signedness
     68#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0
     69#pragma clang diagnostic ignored "-Wcomma"                          // warning: possible misuse of comma operator here
     70#pragma clang diagnostic ignored "-Wreserved-id-macro"              // warning: macro name is a reserved identifier
     71#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.
     72#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
    5373#elif defined(__GNUC__)
     74#pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
    5475#pragma GCC diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
    5576#pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
    5677#pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
     78#pragma GCC diagnostic ignored "-Wstack-protector"          // warning: stack protector not protecting local variables: variable length buffer
     79#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
    5780#endif
    5881
    5982//-------------------------------------------------------------------------
    60 // STB libraries implementation
     83// [SECTION] STB libraries implementation
    6184//-------------------------------------------------------------------------
    6285
    6386// Compile time options:
    64 //#define IMGUI_STB_NAMESPACE           ImGuiStb
     87//#define IMGUI_STB_NAMESPACE           ImStb
    6588//#define IMGUI_STB_TRUETYPE_FILENAME   "my_folder/stb_truetype.h"
    6689//#define IMGUI_STB_RECT_PACK_FILENAME  "my_folder/stb_rect_pack.h"
     
    78101#endif
    79102
    80 #ifdef __clang__
     103#if defined(__clang__)
    81104#pragma clang diagnostic push
    82105#pragma clang diagnostic ignored "-Wunused-function"
    83106#pragma clang diagnostic ignored "-Wmissing-prototypes"
    84107#pragma clang diagnostic ignored "-Wimplicit-fallthrough"
    85 #pragma clang diagnostic ignored "-Wcast-qual"              // warning : cast from 'const xxxx *' to 'xxx *' drops const qualifier //
     108#pragma clang diagnostic ignored "-Wcast-qual"              // warning: cast from 'const xxxx *' to 'xxx *' drops const qualifier
    86109#endif
    87110
    88 #ifdef __GNUC__
     111#if defined(__GNUC__)
    89112#pragma GCC diagnostic push
    90113#pragma GCC diagnostic ignored "-Wtype-limits"              // warning: comparison is always true due to limited range of data type [-Wtype-limits]
     
    92115#endif
    93116
     117#ifndef STB_RECT_PACK_IMPLEMENTATION                        // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
    94118#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
    95119#define STBRP_STATIC
    96 #define STBRP_ASSERT(x)    IM_ASSERT(x)
     120#define STBRP_ASSERT(x)     do { IM_ASSERT(x); } while (0)
     121#define STBRP_SORT          ImQsort
    97122#define STB_RECT_PACK_IMPLEMENTATION
    98123#endif
     
    100125#include IMGUI_STB_RECT_PACK_FILENAME
    101126#else
    102 #include "stb_rect_pack.h"
     127#include "imstb_rectpack.h"
    103128#endif
    104 
     129#endif
     130
     131#ifndef STB_TRUETYPE_IMPLEMENTATION                         // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
    105132#ifndef IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
    106 #define STBTT_malloc(x,u)  ((void)(u), ImGui::MemAlloc(x))
    107 #define STBTT_free(x,u)    ((void)(u), ImGui::MemFree(x))
    108 #define STBTT_assert(x)    IM_ASSERT(x)
     133#define STBTT_malloc(x,u)   ((void)(u), IM_ALLOC(x))
     134#define STBTT_free(x,u)     ((void)(u), IM_FREE(x))
     135#define STBTT_assert(x)     do { IM_ASSERT(x); } while(0)
     136#define STBTT_fmod(x,y)     ImFmod(x,y)
     137#define STBTT_sqrt(x)       ImSqrt(x)
     138#define STBTT_pow(x,y)      ImPow(x,y)
     139#define STBTT_fabs(x)       ImFabs(x)
     140#define STBTT_ifloor(x)     ((int)ImFloorStd(x))
     141#define STBTT_iceil(x)      ((int)ImCeil(x))
    109142#define STBTT_STATIC
    110143#define STB_TRUETYPE_IMPLEMENTATION
     
    115148#include IMGUI_STB_TRUETYPE_FILENAME
    116149#else
    117 #include "stb_truetype.h"
     150#include "imstb_truetype.h"
    118151#endif
    119 
    120 #ifdef __GNUC__
     152#endif
     153
     154#if defined(__GNUC__)
    121155#pragma GCC diagnostic pop
    122156#endif
    123157
    124 #ifdef __clang__
     158#if defined(__clang__)
    125159#pragma clang diagnostic pop
    126160#endif
    127161
    128 #ifdef _MSC_VER
     162#if defined(_MSC_VER)
    129163#pragma warning (pop)
    130164#endif
    131165
    132166#ifdef IMGUI_STB_NAMESPACE
    133 } // namespace ImGuiStb
     167} // namespace ImStb
    134168using namespace IMGUI_STB_NAMESPACE;
    135169#endif
    136170
    137171//-----------------------------------------------------------------------------
    138 // Style functions
     172// [SECTION] Style functions
    139173//-----------------------------------------------------------------------------
    140174
    141175void ImGui::StyleColorsDark(ImGuiStyle* dst)
    142176{
    143    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
    144    ImVec4* colors = style->Colors;
    145 
    146    colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
    147    colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
    148    colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
    149    colors[ImGuiCol_ChildBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.00f);
    150    colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
    151    colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
    152    colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    153    colors[ImGuiCol_FrameBg] = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);
    154    colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
    155    colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
    156    colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
    157    colors[ImGuiCol_TitleBgActive] = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);
    158    colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
    159    colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
    160    colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
    161    colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
    162    colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
    163    colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
    164    colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    165    colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
    166    colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    167    colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
    168    colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    169    colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
    170    colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
    171    colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
    172    colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    173    colors[ImGuiCol_Separator] = colors[ImGuiCol_Border];
    174    colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
    175    colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
    176    colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
    177    colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
    178    colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
    179    colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
    180    colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
    181    colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
    182    colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
    183    colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
    184    colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
    185    colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
    186    colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    187    colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
     177    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
     178    ImVec4* colors = style->Colors;
     179
     180    colors[ImGuiCol_Text]                   = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
     181    colors[ImGuiCol_TextDisabled]           = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
     182    colors[ImGuiCol_WindowBg]               = ImVec4(0.06f, 0.06f, 0.06f, 0.94f);
     183    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
     184    colors[ImGuiCol_PopupBg]                = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
     185    colors[ImGuiCol_Border]                 = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
     186    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
     187    colors[ImGuiCol_FrameBg]                = ImVec4(0.16f, 0.29f, 0.48f, 0.54f);
     188    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
     189    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
     190    colors[ImGuiCol_TitleBg]                = ImVec4(0.04f, 0.04f, 0.04f, 1.00f);
     191    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.16f, 0.29f, 0.48f, 1.00f);
     192    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.00f, 0.00f, 0.00f, 0.51f);
     193    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
     194    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
     195    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
     196    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
     197    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
     198    colors[ImGuiCol_CheckMark]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
     199    colors[ImGuiCol_SliderGrab]             = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
     200    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
     201    colors[ImGuiCol_Button]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
     202    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
     203    colors[ImGuiCol_ButtonActive]           = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
     204    colors[ImGuiCol_Header]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
     205    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
     206    colors[ImGuiCol_HeaderActive]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
     207    colors[ImGuiCol_Separator]              = colors[ImGuiCol_Border];
     208    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
     209    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
     210    colors[ImGuiCol_ResizeGrip]             = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
     211    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
     212    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
     213    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.80f);
     214    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
     215    colors[ImGuiCol_TabActive]              = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
     216    colors[ImGuiCol_TabUnfocused]           = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
     217    colors[ImGuiCol_TabUnfocusedActive]     = ImLerp(colors[ImGuiCol_TabActive],    colors[ImGuiCol_TitleBg], 0.40f);
     218    colors[ImGuiCol_PlotLines]              = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
     219    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
     220    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
     221    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
     222    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
     223    colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
     224    colors[ImGuiCol_NavHighlight]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
     225    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
     226    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
     227    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
    188228}
    189229
    190230void ImGui::StyleColorsClassic(ImGuiStyle* dst)
    191231{
    192    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
    193    ImVec4* colors = style->Colors;
    194 
    195    colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
    196    colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
    197    colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f);
    198    colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    199    colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
    200    colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
    201    colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    202    colors[ImGuiCol_FrameBg] = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
    203    colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);
    204    colors[ImGuiCol_FrameBgActive] = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);
    205    colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
    206    colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
    207    colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
    208    colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
    209    colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
    210    colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
    211    colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
    212    colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
    213    colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
    214    colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
    215    colors[ImGuiCol_SliderGrabActive] = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
    216    colors[ImGuiCol_Button] = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
    217    colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);
    218    colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
    219    colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
    220    colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
    221    colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
    222    colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
    223    colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
    224    colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
    225    colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
    226    colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
    227    colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
    228    colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
    229    colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
    230    colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
    231    colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
    232    colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
    233    colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
    234    colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
    235    colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];
    236    colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
     232    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
     233    ImVec4* colors = style->Colors;
     234
     235    colors[ImGuiCol_Text]                   = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
     236    colors[ImGuiCol_TextDisabled]           = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
     237    colors[ImGuiCol_WindowBg]               = ImVec4(0.00f, 0.00f, 0.00f, 0.70f);
     238    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
     239    colors[ImGuiCol_PopupBg]                = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
     240    colors[ImGuiCol_Border]                 = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
     241    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
     242    colors[ImGuiCol_FrameBg]                = ImVec4(0.43f, 0.43f, 0.43f, 0.39f);
     243    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.47f, 0.47f, 0.69f, 0.40f);
     244    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.42f, 0.41f, 0.64f, 0.69f);
     245    colors[ImGuiCol_TitleBg]                = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
     246    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
     247    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
     248    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
     249    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
     250    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
     251    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
     252    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
     253    colors[ImGuiCol_CheckMark]              = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
     254    colors[ImGuiCol_SliderGrab]             = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
     255    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.41f, 0.39f, 0.80f, 0.60f);
     256    colors[ImGuiCol_Button]                 = ImVec4(0.35f, 0.40f, 0.61f, 0.62f);
     257    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.40f, 0.48f, 0.71f, 0.79f);
     258    colors[ImGuiCol_ButtonActive]           = ImVec4(0.46f, 0.54f, 0.80f, 1.00f);
     259    colors[ImGuiCol_Header]                 = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
     260    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
     261    colors[ImGuiCol_HeaderActive]           = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
     262    colors[ImGuiCol_Separator]              = ImVec4(0.50f, 0.50f, 0.50f, 0.60f);
     263    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
     264    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
     265    colors[ImGuiCol_ResizeGrip]             = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
     266    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
     267    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
     268    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.80f);
     269    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
     270    colors[ImGuiCol_TabActive]              = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
     271    colors[ImGuiCol_TabUnfocused]           = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
     272    colors[ImGuiCol_TabUnfocusedActive]     = ImLerp(colors[ImGuiCol_TabActive],    colors[ImGuiCol_TitleBg], 0.40f);
     273    colors[ImGuiCol_PlotLines]              = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
     274    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
     275    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
     276    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
     277    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
     278    colors[ImGuiCol_DragDropTarget]         = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
     279    colors[ImGuiCol_NavHighlight]           = colors[ImGuiCol_HeaderHovered];
     280    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
     281    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
     282    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
    237283}
    238284
     
    240286void ImGui::StyleColorsLight(ImGuiStyle* dst)
    241287{
    242    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
    243    ImVec4* colors = style->Colors;
    244 
    245    colors[ImGuiCol_Text] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
    246    colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
    247    colors[ImGuiCol_WindowBg] = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
    248    colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    249    colors[ImGuiCol_PopupBg] = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
    250    colors[ImGuiCol_Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
    251    colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
    252    colors[ImGuiCol_FrameBg] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
    253    colors[ImGuiCol_FrameBgHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
    254    colors[ImGuiCol_FrameBgActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
    255    colors[ImGuiCol_TitleBg] = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
    256    colors[ImGuiCol_TitleBgActive] = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
    257    colors[ImGuiCol_TitleBgCollapsed] = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
    258    colors[ImGuiCol_MenuBarBg] = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
    259    colors[ImGuiCol_ScrollbarBg] = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
    260    colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);
    261    colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
    262    colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
    263    colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    264    colors[ImGuiCol_SliderGrab] = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
    265    colors[ImGuiCol_SliderGrabActive] = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
    266    colors[ImGuiCol_Button] = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
    267    colors[ImGuiCol_ButtonHovered] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    268    colors[ImGuiCol_ButtonActive] = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
    269    colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
    270    colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
    271    colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
    272    colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
    273    colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
    274    colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
    275    colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
    276    colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
    277    colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
    278    colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
    279    colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
    280    colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
    281    colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);
    282    colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
    283    colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
    284    colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
    285    colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];
    286    colors[ImGuiCol_NavWindowingHighlight] = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);
     288    ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
     289    ImVec4* colors = style->Colors;
     290
     291    colors[ImGuiCol_Text]                   = ImVec4(0.00f, 0.00f, 0.00f, 1.00f);
     292    colors[ImGuiCol_TextDisabled]           = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
     293    colors[ImGuiCol_WindowBg]               = ImVec4(0.94f, 0.94f, 0.94f, 1.00f);
     294    colors[ImGuiCol_ChildBg]                = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
     295    colors[ImGuiCol_PopupBg]                = ImVec4(1.00f, 1.00f, 1.00f, 0.98f);
     296    colors[ImGuiCol_Border]                 = ImVec4(0.00f, 0.00f, 0.00f, 0.30f);
     297    colors[ImGuiCol_BorderShadow]           = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
     298    colors[ImGuiCol_FrameBg]                = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
     299    colors[ImGuiCol_FrameBgHovered]         = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
     300    colors[ImGuiCol_FrameBgActive]          = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
     301    colors[ImGuiCol_TitleBg]                = ImVec4(0.96f, 0.96f, 0.96f, 1.00f);
     302    colors[ImGuiCol_TitleBgActive]          = ImVec4(0.82f, 0.82f, 0.82f, 1.00f);
     303    colors[ImGuiCol_TitleBgCollapsed]       = ImVec4(1.00f, 1.00f, 1.00f, 0.51f);
     304    colors[ImGuiCol_MenuBarBg]              = ImVec4(0.86f, 0.86f, 0.86f, 1.00f);
     305    colors[ImGuiCol_ScrollbarBg]            = ImVec4(0.98f, 0.98f, 0.98f, 0.53f);
     306    colors[ImGuiCol_ScrollbarGrab]          = ImVec4(0.69f, 0.69f, 0.69f, 0.80f);
     307    colors[ImGuiCol_ScrollbarGrabHovered]   = ImVec4(0.49f, 0.49f, 0.49f, 0.80f);
     308    colors[ImGuiCol_ScrollbarGrabActive]    = ImVec4(0.49f, 0.49f, 0.49f, 1.00f);
     309    colors[ImGuiCol_CheckMark]              = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
     310    colors[ImGuiCol_SliderGrab]             = ImVec4(0.26f, 0.59f, 0.98f, 0.78f);
     311    colors[ImGuiCol_SliderGrabActive]       = ImVec4(0.46f, 0.54f, 0.80f, 0.60f);
     312    colors[ImGuiCol_Button]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.40f);
     313    colors[ImGuiCol_ButtonHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
     314    colors[ImGuiCol_ButtonActive]           = ImVec4(0.06f, 0.53f, 0.98f, 1.00f);
     315    colors[ImGuiCol_Header]                 = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
     316    colors[ImGuiCol_HeaderHovered]          = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
     317    colors[ImGuiCol_HeaderActive]           = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
     318    colors[ImGuiCol_Separator]              = ImVec4(0.39f, 0.39f, 0.39f, 0.62f);
     319    colors[ImGuiCol_SeparatorHovered]       = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
     320    colors[ImGuiCol_SeparatorActive]        = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
     321    colors[ImGuiCol_ResizeGrip]             = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
     322    colors[ImGuiCol_ResizeGripHovered]      = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
     323    colors[ImGuiCol_ResizeGripActive]       = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
     324    colors[ImGuiCol_Tab]                    = ImLerp(colors[ImGuiCol_Header],       colors[ImGuiCol_TitleBgActive], 0.90f);
     325    colors[ImGuiCol_TabHovered]             = colors[ImGuiCol_HeaderHovered];
     326    colors[ImGuiCol_TabActive]              = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
     327    colors[ImGuiCol_TabUnfocused]           = ImLerp(colors[ImGuiCol_Tab],          colors[ImGuiCol_TitleBg], 0.80f);
     328    colors[ImGuiCol_TabUnfocusedActive]     = ImLerp(colors[ImGuiCol_TabActive],    colors[ImGuiCol_TitleBg], 0.40f);
     329    colors[ImGuiCol_PlotLines]              = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
     330    colors[ImGuiCol_PlotLinesHovered]       = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
     331    colors[ImGuiCol_PlotHistogram]          = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
     332    colors[ImGuiCol_PlotHistogramHovered]   = ImVec4(1.00f, 0.45f, 0.00f, 1.00f);
     333    colors[ImGuiCol_TextSelectedBg]         = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
     334    colors[ImGuiCol_DragDropTarget]         = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
     335    colors[ImGuiCol_NavHighlight]           = colors[ImGuiCol_HeaderHovered];
     336    colors[ImGuiCol_NavWindowingHighlight]  = ImVec4(0.70f, 0.70f, 0.70f, 0.70f);
     337    colors[ImGuiCol_NavWindowingDimBg]      = ImVec4(0.20f, 0.20f, 0.20f, 0.20f);
     338    colors[ImGuiCol_ModalWindowDimBg]       = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
    287339}
    288340
    289341//-----------------------------------------------------------------------------
    290 // ImDrawListData
     342// [SECTION] ImDrawList
    291343//-----------------------------------------------------------------------------
    292344
    293345ImDrawListSharedData::ImDrawListSharedData()
    294346{
    295    Font = NULL;
    296    FontSize = 0.0f;
    297    CurveTessellationTol = 0.0f;
    298    ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f);
    299 
    300    // Const data
    301    for (int i = 0; i < IM_ARRAYSIZE(CircleVtx12); i++)
    302    {
    303       const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(CircleVtx12);
    304       CircleVtx12[i] = ImVec2(cosf(a), sinf(a));
    305    }
    306 }
    307 
    308 //-----------------------------------------------------------------------------
    309 // ImDrawList
    310 //-----------------------------------------------------------------------------
    311 
    312 void ImDrawList::Clear()
    313 {
    314    CmdBuffer.resize(0);
    315    IdxBuffer.resize(0);
    316    VtxBuffer.resize(0);
    317    Flags = ImDrawListFlags_AntiAliasedLines | ImDrawListFlags_AntiAliasedFill;
    318    _VtxCurrentIdx = 0;
    319    _VtxWritePtr = NULL;
    320    _IdxWritePtr = NULL;
    321    _ClipRectStack.resize(0);
    322    _TextureIdStack.resize(0);
    323    _Path.resize(0);
    324    _ChannelsCurrent = 0;
    325    _ChannelsCount = 1;
    326    // NB: Do not clear channels so our allocations are re-used after the first frame.
    327 }
    328 
    329 void ImDrawList::ClearFreeMemory()
    330 {
    331    CmdBuffer.clear();
    332    IdxBuffer.clear();
    333    VtxBuffer.clear();
    334    _VtxCurrentIdx = 0;
    335    _VtxWritePtr = NULL;
    336    _IdxWritePtr = NULL;
    337    _ClipRectStack.clear();
    338    _TextureIdStack.clear();
    339    _Path.clear();
    340    _ChannelsCurrent = 0;
    341    _ChannelsCount = 1;
    342    for (int i = 0; i < _Channels.Size; i++)
    343    {
    344       if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0]));  // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
    345       _Channels[i].CmdBuffer.clear();
    346       _Channels[i].IdxBuffer.clear();
    347    }
    348    _Channels.clear();
     347    Font = NULL;
     348    FontSize = 0.0f;
     349    CurveTessellationTol = 0.0f;
     350    CircleSegmentMaxError = 0.0f;
     351    ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f);
     352    InitialFlags = ImDrawListFlags_None;
     353
     354    // Lookup tables
     355    for (int i = 0; i < IM_ARRAYSIZE(ArcFastVtx); i++)
     356    {
     357        const float a = ((float)i * 2 * IM_PI) / (float)IM_ARRAYSIZE(ArcFastVtx);
     358        ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
     359    }
     360    memset(CircleSegmentCounts, 0, sizeof(CircleSegmentCounts)); // This will be set by SetCircleSegmentMaxError()
     361    TexUvLines = NULL;
     362}
     363
     364void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error)
     365{
     366    if (CircleSegmentMaxError == max_error)
     367        return;
     368    CircleSegmentMaxError = max_error;
     369    for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++)
     370    {
     371        const float radius = i + 1.0f;
     372        const int segment_count = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError);
     373        CircleSegmentCounts[i] = (ImU8)ImMin(segment_count, 255);
     374    }
     375}
     376
     377// Initialize before use in a new frame. We always have a command ready in the buffer.
     378void ImDrawList::_ResetForNewFrame()
     379{
     380    // Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
     381    // (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC)
     382    IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);
     383    IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));
     384    IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
     385
     386    CmdBuffer.resize(0);
     387    IdxBuffer.resize(0);
     388    VtxBuffer.resize(0);
     389    Flags = _Data->InitialFlags;
     390    memset(&_CmdHeader, 0, sizeof(_CmdHeader));
     391    _VtxCurrentIdx = 0;
     392    _VtxWritePtr = NULL;
     393    _IdxWritePtr = NULL;
     394    _ClipRectStack.resize(0);
     395    _TextureIdStack.resize(0);
     396    _Path.resize(0);
     397    _Splitter.Clear();
     398    CmdBuffer.push_back(ImDrawCmd());
     399}
     400
     401void ImDrawList::_ClearFreeMemory()
     402{
     403    CmdBuffer.clear();
     404    IdxBuffer.clear();
     405    VtxBuffer.clear();
     406    Flags = ImDrawListFlags_None;
     407    _VtxCurrentIdx = 0;
     408    _VtxWritePtr = NULL;
     409    _IdxWritePtr = NULL;
     410    _ClipRectStack.clear();
     411    _TextureIdStack.clear();
     412    _Path.clear();
     413    _Splitter.ClearFreeMemory();
    349414}
    350415
    351416ImDrawList* ImDrawList::CloneOutput() const
    352417{
    353    ImDrawList* dst = IM_NEW(ImDrawList(NULL));
    354    dst->CmdBuffer = CmdBuffer;
    355    dst->IdxBuffer = IdxBuffer;
    356    dst->VtxBuffer = VtxBuffer;
    357    dst->Flags = Flags;
    358    return dst;
    359 }
    360 
    361 // Using macros because C++ is a terrible language, we want guaranteed inline, no code in header, and no overhead in Debug builds
    362 #define GetCurrentClipRect()    (_ClipRectStack.Size ? _ClipRectStack.Data[_ClipRectStack.Size-1]  : _Data->ClipRectFullscreen)
    363 #define GetCurrentTextureId()   (_TextureIdStack.Size ? _TextureIdStack.Data[_TextureIdStack.Size-1] : NULL)
     418    ImDrawList* dst = IM_NEW(ImDrawList(_Data));
     419    dst->CmdBuffer = CmdBuffer;
     420    dst->IdxBuffer = IdxBuffer;
     421    dst->VtxBuffer = VtxBuffer;
     422    dst->Flags = Flags;
     423    return dst;
     424}
    364425
    365426void ImDrawList::AddDrawCmd()
    366427{
    367    ImDrawCmd draw_cmd;
    368    draw_cmd.ClipRect = GetCurrentClipRect();
    369    draw_cmd.TextureId = GetCurrentTextureId();
    370 
    371    IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
    372    CmdBuffer.push_back(draw_cmd);
     428    ImDrawCmd draw_cmd;
     429    draw_cmd.ClipRect = _CmdHeader.ClipRect;    // Same as calling ImDrawCmd_HeaderCopy()
     430    draw_cmd.TextureId = _CmdHeader.TextureId;
     431    draw_cmd.VtxOffset = _CmdHeader.VtxOffset;
     432    draw_cmd.IdxOffset = IdxBuffer.Size;
     433
     434    IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
     435    CmdBuffer.push_back(draw_cmd);
     436}
     437
     438// Pop trailing draw command (used before merging or presenting to user)
     439// Note that this leaves the ImDrawList in a state unfit for further commands, as most code assume that CmdBuffer.Size > 0 && CmdBuffer.back().UserCallback == NULL
     440void ImDrawList::_PopUnusedDrawCmd()
     441{
     442    if (CmdBuffer.Size == 0)
     443        return;
     444    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
     445    if (curr_cmd->ElemCount == 0 && curr_cmd->UserCallback == NULL)
     446        CmdBuffer.pop_back();
    373447}
    374448
    375449void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
    376450{
    377    ImDrawCmd* current_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
    378    if (!current_cmd || current_cmd->ElemCount != 0 || current_cmd->UserCallback != NULL)
    379    {
    380       AddDrawCmd();
    381       current_cmd = &CmdBuffer.back();
    382    }
    383    current_cmd->UserCallback = callback;
    384    current_cmd->UserCallbackData = callback_data;
    385 
    386    AddDrawCmd(); // Force a new command after us (see comment below)
    387 }
     451    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
     452    IM_ASSERT(curr_cmd->UserCallback == NULL);
     453    if (curr_cmd->ElemCount != 0)
     454    {
     455        AddDrawCmd();
     456        curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
     457    }
     458    curr_cmd->UserCallback = callback;
     459    curr_cmd->UserCallbackData = callback_data;
     460
     461    AddDrawCmd(); // Force a new command after us (see comment below)
     462}
     463
     464// Compare ClipRect, TextureId and VtxOffset with a single memcmp()
     465#define ImDrawCmd_HeaderSize                        (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
     466#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS)   (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize))    // Compare ClipRect, TextureId, VtxOffset
     467#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC)      (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize))    // Copy ClipRect, TextureId, VtxOffset
    388468
    389469// Our scheme may appears a bit unusual, basically we want the most-common calls AddLine AddRect etc. to not have to perform any check so we always have a command ready in the stack.
    390470// The cost of figuring out if a new command has to be added or if we can merge is paid in those Update** functions only.
    391 void ImDrawList::UpdateClipRect()
    392 {
    393    // If current command is used with different settings we need to add a new command
    394    const ImVec4 curr_clip_rect = GetCurrentClipRect();
    395    ImDrawCmd* curr_cmd = CmdBuffer.Size > 0 ? &CmdBuffer.Data[CmdBuffer.Size - 1] : NULL;
    396    if (!curr_cmd || (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) != 0) || curr_cmd->UserCallback != NULL)
    397    {
    398       AddDrawCmd();
    399       return;
    400    }
    401 
    402    // Try to merge with previous command if it matches, else use current command
    403    ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
    404    if (curr_cmd->ElemCount == 0 && prev_cmd && memcmp(&prev_cmd->ClipRect, &curr_clip_rect, sizeof(ImVec4)) == 0 && prev_cmd->TextureId == GetCurrentTextureId() && prev_cmd->UserCallback == NULL)
    405       CmdBuffer.pop_back();
    406    else
    407       curr_cmd->ClipRect = curr_clip_rect;
    408 }
    409 
    410 void ImDrawList::UpdateTextureID()
    411 {
    412    // If current command is used with different settings we need to add a new command
    413    const ImTextureID curr_texture_id = GetCurrentTextureId();
    414    ImDrawCmd* curr_cmd = CmdBuffer.Size ? &CmdBuffer.back() : NULL;
    415    if (!curr_cmd || (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != curr_texture_id) || curr_cmd->UserCallback != NULL)
    416    {
    417       AddDrawCmd();
    418       return;
    419    }
    420 
    421    // Try to merge with previous command if it matches, else use current command
    422    ImDrawCmd* prev_cmd = CmdBuffer.Size > 1 ? curr_cmd - 1 : NULL;
    423    if (curr_cmd->ElemCount == 0 && prev_cmd && prev_cmd->TextureId == curr_texture_id && memcmp(&prev_cmd->ClipRect, &GetCurrentClipRect(), sizeof(ImVec4)) == 0 && prev_cmd->UserCallback == NULL)
    424       CmdBuffer.pop_back();
    425    else
    426       curr_cmd->TextureId = curr_texture_id;
    427 }
    428 
    429 #undef GetCurrentClipRect
    430 #undef GetCurrentTextureId
     471void ImDrawList::_OnChangedClipRect()
     472{
     473    // If current command is used with different settings we need to add a new command
     474    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
     475    if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
     476    {
     477        AddDrawCmd();
     478        return;
     479    }
     480    IM_ASSERT(curr_cmd->UserCallback == NULL);
     481
     482    // Try to merge with previous command if it matches, else use current command
     483    ImDrawCmd* prev_cmd = curr_cmd - 1;
     484    if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
     485    {
     486        CmdBuffer.pop_back();
     487        return;
     488    }
     489
     490    curr_cmd->ClipRect = _CmdHeader.ClipRect;
     491}
     492
     493void ImDrawList::_OnChangedTextureID()
     494{
     495    // If current command is used with different settings we need to add a new command
     496    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
     497    if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId)
     498    {
     499        AddDrawCmd();
     500        return;
     501    }
     502    IM_ASSERT(curr_cmd->UserCallback == NULL);
     503
     504    // Try to merge with previous command if it matches, else use current command
     505    ImDrawCmd* prev_cmd = curr_cmd - 1;
     506    if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
     507    {
     508        CmdBuffer.pop_back();
     509        return;
     510    }
     511
     512    curr_cmd->TextureId = _CmdHeader.TextureId;
     513}
     514
     515void ImDrawList::_OnChangedVtxOffset()
     516{
     517    // We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.
     518    _VtxCurrentIdx = 0;
     519    ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
     520    //IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349
     521    if (curr_cmd->ElemCount != 0)
     522    {
     523        AddDrawCmd();
     524        return;
     525    }
     526    IM_ASSERT(curr_cmd->UserCallback == NULL);
     527    curr_cmd->VtxOffset = _CmdHeader.VtxOffset;
     528}
    431529
    432530// Render-level scissoring. This is passed down to your render function but not used for CPU-side coarse clipping. Prefer using higher-level ImGui::PushClipRect() to affect logic (hit-testing and widget culling)
    433531void ImDrawList::PushClipRect(ImVec2 cr_min, ImVec2 cr_max, bool intersect_with_current_clip_rect)
    434532{
    435    ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
    436    if (intersect_with_current_clip_rect && _ClipRectStack.Size)
    437    {
    438       ImVec4 current = _ClipRectStack.Data[_ClipRectStack.Size - 1];
    439       if (cr.x < current.x) cr.x = current.x;
    440       if (cr.y < current.y) cr.y = current.y;
    441       if (cr.z > current.z) cr.z = current.z;
    442       if (cr.w > current.w) cr.w = current.w;
    443    }
    444    cr.z = ImMax(cr.x, cr.z);
    445    cr.w = ImMax(cr.y, cr.w);
    446 
    447    _ClipRectStack.push_back(cr);
    448    UpdateClipRect();
     533    ImVec4 cr(cr_min.x, cr_min.y, cr_max.x, cr_max.y);
     534    if (intersect_with_current_clip_rect)
     535    {
     536        ImVec4 current = _CmdHeader.ClipRect;
     537        if (cr.x < current.x) cr.x = current.x;
     538        if (cr.y < current.y) cr.y = current.y;
     539        if (cr.z > current.z) cr.z = current.z;
     540        if (cr.w > current.w) cr.w = current.w;
     541    }
     542    cr.z = ImMax(cr.x, cr.z);
     543    cr.w = ImMax(cr.y, cr.w);
     544
     545    _ClipRectStack.push_back(cr);
     546    _CmdHeader.ClipRect = cr;
     547    _OnChangedClipRect();
    449548}
    450549
    451550void ImDrawList::PushClipRectFullScreen()
    452551{
    453    PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));
     552    PushClipRect(ImVec2(_Data->ClipRectFullscreen.x, _Data->ClipRectFullscreen.y), ImVec2(_Data->ClipRectFullscreen.z, _Data->ClipRectFullscreen.w));
    454553}
    455554
    456555void ImDrawList::PopClipRect()
    457556{
    458    IM_ASSERT(_ClipRectStack.Size > 0);
    459    _ClipRectStack.pop_back();
    460    UpdateClipRect();
     557    _ClipRectStack.pop_back();
     558    _CmdHeader.ClipRect = (_ClipRectStack.Size == 0) ? _Data->ClipRectFullscreen : _ClipRectStack.Data[_ClipRectStack.Size - 1];
     559    _OnChangedClipRect();
    461560}
    462561
    463562void ImDrawList::PushTextureID(ImTextureID texture_id)
    464563{
    465    _TextureIdStack.push_back(texture_id);
    466    UpdateTextureID();
     564    _TextureIdStack.push_back(texture_id);
     565    _CmdHeader.TextureId = texture_id;
     566    _OnChangedTextureID();
    467567}
    468568
    469569void ImDrawList::PopTextureID()
    470570{
    471    IM_ASSERT(_TextureIdStack.Size > 0);
    472    _TextureIdStack.pop_back();
    473    UpdateTextureID();
    474 }
    475 
    476 void ImDrawList::ChannelsSplit(int channels_count)
    477 {
    478    IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1);
    479    int old_channels_count = _Channels.Size;
    480    if (old_channels_count < channels_count)
    481       _Channels.resize(channels_count);
    482    _ChannelsCount = channels_count;
    483 
    484    // _Channels[] (24/32 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer
    485    // The content of _Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to.
    486    // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer
    487    memset(&_Channels[0], 0, sizeof(ImDrawChannel));
    488    for (int i = 1; i < channels_count; i++)
    489    {
    490       if (i >= old_channels_count)
    491       {
    492          IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
    493       }
    494       else
    495       {
    496          _Channels[i].CmdBuffer.resize(0);
    497          _Channels[i].IdxBuffer.resize(0);
    498       }
    499       if (_Channels[i].CmdBuffer.Size == 0)
    500       {
    501          ImDrawCmd draw_cmd;
    502          draw_cmd.ClipRect = _ClipRectStack.back();
    503          draw_cmd.TextureId = _TextureIdStack.back();
    504          _Channels[i].CmdBuffer.push_back(draw_cmd);
    505       }
    506    }
    507 }
    508 
    509 void ImDrawList::ChannelsMerge()
    510 {
    511    // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
    512    if (_ChannelsCount <= 1)
    513       return;
    514 
    515    ChannelsSetCurrent(0);
    516    if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0)
    517       CmdBuffer.pop_back();
    518 
    519    int new_cmd_buffer_count = 0, new_idx_buffer_count = 0;
    520    for (int i = 1; i < _ChannelsCount; i++)
    521    {
    522       ImDrawChannel& ch = _Channels[i];
    523       if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0)
    524          ch.CmdBuffer.pop_back();
    525       new_cmd_buffer_count += ch.CmdBuffer.Size;
    526       new_idx_buffer_count += ch.IdxBuffer.Size;
    527    }
    528    CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count);
    529    IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count);
    530 
    531    ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count;
    532    _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count;
    533    for (int i = 1; i < _ChannelsCount; i++)
    534    {
    535       ImDrawChannel& ch = _Channels[i];
    536       if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
    537       if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; }
    538    }
    539    UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call.
    540    _ChannelsCount = 1;
    541 }
    542 
    543 void ImDrawList::ChannelsSetCurrent(int idx)
    544 {
    545    IM_ASSERT(idx < _ChannelsCount);
    546    if (_ChannelsCurrent == idx) return;
    547    memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times
    548    memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer));
    549    _ChannelsCurrent = idx;
    550    memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer));
    551    memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer));
    552    _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
    553 }
    554 
    555 // NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
     571    _TextureIdStack.pop_back();
     572    _CmdHeader.TextureId = (_TextureIdStack.Size == 0) ? (ImTextureID)NULL : _TextureIdStack.Data[_TextureIdStack.Size - 1];
     573    _OnChangedTextureID();
     574}
     575
     576// Reserve space for a number of vertices and indices.
     577// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or
     578// submit the intermediate results. PrimUnreserve() can be used to release unused allocations.
    556579void ImDrawList::PrimReserve(int idx_count, int vtx_count)
    557580{
    558    ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size - 1];
    559    draw_cmd.ElemCount += idx_count;
    560 
    561    int vtx_buffer_old_size = VtxBuffer.Size;
    562    VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
    563    _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
    564 
    565    int idx_buffer_old_size = IdxBuffer.Size;
    566    IdxBuffer.resize(idx_buffer_old_size + idx_count);
    567    _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
     581    // Large mesh support (when enabled)
     582    IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
     583    if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))
     584    {
     585        // FIXME: In theory we should be testing that vtx_count <64k here.
     586        // In practice, RenderText() relies on reserving ahead for a worst case scenario so it is currently useful for us
     587        // to not make that check until we rework the text functions to handle clipping and large horizontal lines better.
     588        _CmdHeader.VtxOffset = VtxBuffer.Size;
     589        _OnChangedVtxOffset();
     590    }
     591
     592    ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
     593    draw_cmd->ElemCount += idx_count;
     594
     595    int vtx_buffer_old_size = VtxBuffer.Size;
     596    VtxBuffer.resize(vtx_buffer_old_size + vtx_count);
     597    _VtxWritePtr = VtxBuffer.Data + vtx_buffer_old_size;
     598
     599    int idx_buffer_old_size = IdxBuffer.Size;
     600    IdxBuffer.resize(idx_buffer_old_size + idx_count);
     601    _IdxWritePtr = IdxBuffer.Data + idx_buffer_old_size;
     602}
     603
     604// Release the a number of reserved vertices/indices from the end of the last reservation made with PrimReserve().
     605void ImDrawList::PrimUnreserve(int idx_count, int vtx_count)
     606{
     607    IM_ASSERT_PARANOID(idx_count >= 0 && vtx_count >= 0);
     608
     609    ImDrawCmd* draw_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
     610    draw_cmd->ElemCount -= idx_count;
     611    VtxBuffer.shrink(VtxBuffer.Size - vtx_count);
     612    IdxBuffer.shrink(IdxBuffer.Size - idx_count);
    568613}
    569614
     
    571616void ImDrawList::PrimRect(const ImVec2& a, const ImVec2& c, ImU32 col)
    572617{
    573    ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);
    574    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
    575    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);
    576    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);
    577    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
    578    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
    579    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
    580    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
    581    _VtxWritePtr += 4;
    582    _VtxCurrentIdx += 4;
    583    _IdxWritePtr += 6;
     618    ImVec2 b(c.x, a.y), d(a.x, c.y), uv(_Data->TexUvWhitePixel);
     619    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
     620    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
     621    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
     622    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
     623    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
     624    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
     625    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
     626    _VtxWritePtr += 4;
     627    _VtxCurrentIdx += 4;
     628    _IdxWritePtr += 6;
    584629}
    585630
    586631void ImDrawList::PrimRectUV(const ImVec2& a, const ImVec2& c, const ImVec2& uv_a, const ImVec2& uv_c, ImU32 col)
    587632{
    588    ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y);
    589    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
    590    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);
    591    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);
    592    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
    593    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
    594    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
    595    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
    596    _VtxWritePtr += 4;
    597    _VtxCurrentIdx += 4;
    598    _IdxWritePtr += 6;
     633    ImVec2 b(c.x, a.y), d(a.x, c.y), uv_b(uv_c.x, uv_a.y), uv_d(uv_a.x, uv_c.y);
     634    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
     635    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
     636    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
     637    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
     638    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
     639    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
     640    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
     641    _VtxWritePtr += 4;
     642    _VtxCurrentIdx += 4;
     643    _IdxWritePtr += 6;
    599644}
    600645
    601646void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col)
    602647{
    603    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
    604    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx + 2);
    605    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx + 3);
    606    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
    607    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
    608    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
    609    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
    610    _VtxWritePtr += 4;
    611    _VtxCurrentIdx += 4;
    612    _IdxWritePtr += 6;
    613 }
     648    ImDrawIdx idx = (ImDrawIdx)_VtxCurrentIdx;
     649    _IdxWritePtr[0] = idx; _IdxWritePtr[1] = (ImDrawIdx)(idx+1); _IdxWritePtr[2] = (ImDrawIdx)(idx+2);
     650    _IdxWritePtr[3] = idx; _IdxWritePtr[4] = (ImDrawIdx)(idx+2); _IdxWritePtr[5] = (ImDrawIdx)(idx+3);
     651    _VtxWritePtr[0].pos = a; _VtxWritePtr[0].uv = uv_a; _VtxWritePtr[0].col = col;
     652    _VtxWritePtr[1].pos = b; _VtxWritePtr[1].uv = uv_b; _VtxWritePtr[1].col = col;
     653    _VtxWritePtr[2].pos = c; _VtxWritePtr[2].uv = uv_c; _VtxWritePtr[2].col = col;
     654    _VtxWritePtr[3].pos = d; _VtxWritePtr[3].uv = uv_d; _VtxWritePtr[3].col = col;
     655    _VtxWritePtr += 4;
     656    _VtxCurrentIdx += 4;
     657    _IdxWritePtr += 6;
     658}
     659
     660// On AddPolyline() and AddConvexPolyFilled() we intentionally avoid using ImVec2 and superfluous function calls to optimize debug/non-inlined builds.
     661// Those macros expects l-values.
     662#define IM_NORMALIZE2F_OVER_ZERO(VX,VY)     do { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = 1.0f / ImSqrt(d2); VX *= inv_len; VY *= inv_len; } } while (0)
     663#define IM_FIXNORMAL2F(VX,VY)               do { float d2 = VX*VX + VY*VY; if (d2 < 0.5f) d2 = 0.5f; float inv_lensq = 1.0f / d2; VX *= inv_lensq; VY *= inv_lensq; } while (0)
    614664
    615665// TODO: Thickness anti-aliased lines cap are missing their AA fringe.
     666// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
    616667void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, bool closed, float thickness)
    617668{
    618    if (points_count < 2)
    619       return;
    620 
    621    const ImVec2 uv = _Data->TexUvWhitePixel;
    622 
    623    int count = points_count;
    624    if (!closed)
    625       count = points_count - 1;
    626 
    627    const bool thick_line = thickness > 1.0f;
    628    if (Flags & ImDrawListFlags_AntiAliasedLines)
    629    {
    630       // Anti-aliased stroke
    631       const float AA_SIZE = 1.0f;
    632       const ImU32 col_trans = col & ~IM_COL32_A_MASK;
    633 
    634       const int idx_count = thick_line ? count * 18 : count * 12;
    635       const int vtx_count = thick_line ? points_count * 4 : points_count * 3;
    636       PrimReserve(idx_count, vtx_count);
    637 
    638       // Temporary buffer
    639       ImVec2* temp_normals = (ImVec2*)alloca(points_count * (thick_line ? 5 : 3) * sizeof(ImVec2));
    640       ImVec2* temp_points = temp_normals + points_count;
    641 
    642       for (int i1 = 0; i1 < count; i1++)
    643       {
    644          const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
    645          ImVec2 diff = points[i2] - points[i1];
    646          diff *= ImInvLength(diff, 1.0f);
    647          temp_normals[i1].x = diff.y;
    648          temp_normals[i1].y = -diff.x;
    649       }
    650       if (!closed)
    651          temp_normals[points_count - 1] = temp_normals[points_count - 2];
    652 
    653       if (!thick_line)
    654       {
    655          if (!closed)
    656          {
    657             temp_points[0] = points[0] + temp_normals[0] * AA_SIZE;
    658             temp_points[1] = points[0] - temp_normals[0] * AA_SIZE;
    659             temp_points[(points_count - 1) * 2 + 0] = points[points_count - 1] + temp_normals[points_count - 1] * AA_SIZE;
    660             temp_points[(points_count - 1) * 2 + 1] = points[points_count - 1] - temp_normals[points_count - 1] * AA_SIZE;
    661          }
    662 
    663          // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
    664          unsigned int idx1 = _VtxCurrentIdx;
    665          for (int i1 = 0; i1 < count; i1++)
    666          {
     669    if (points_count < 2)
     670        return;
     671
     672    const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
     673    const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw
     674    const bool thick_line = (thickness > 1.0f);
     675
     676    if (Flags & ImDrawListFlags_AntiAliasedLines)
     677    {
     678        // Anti-aliased stroke
     679        const float AA_SIZE = 1.0f;
     680        const ImU32 col_trans = col & ~IM_COL32_A_MASK;
     681
     682        // Thicknesses <1.0 should behave like thickness 1.0
     683        thickness = ImMax(thickness, 1.0f);
     684        const int integer_thickness = (int)thickness;
     685        const float fractional_thickness = thickness - integer_thickness;
     686
     687        // Do we want to draw this line using a texture?
     688        // - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved.
     689        // - If AA_SIZE is not 1.0f we cannot use the texture path.
     690        const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f);
     691
     692        // We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off
     693        IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines));
     694
     695        const int idx_count = use_texture ? (count * 6) : (thick_line ? count * 18 : count * 12);
     696        const int vtx_count = use_texture ? (points_count * 2) : (thick_line ? points_count * 4 : points_count * 3);
     697        PrimReserve(idx_count, vtx_count);
     698
     699        // Temporary buffer
     700        // The first <points_count> items are normals at each line point, then after that there are either 2 or 4 temp points for each line point
     701        ImVec2* temp_normals = (ImVec2*)alloca(points_count * ((use_texture || !thick_line) ? 3 : 5) * sizeof(ImVec2)); //-V630
     702        ImVec2* temp_points = temp_normals + points_count;
     703
     704        // Calculate normals (tangents) for each line segment
     705        for (int i1 = 0; i1 < count; i1++)
     706        {
    667707            const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
    668             unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : idx1 + 3;
    669 
     708            float dx = points[i2].x - points[i1].x;
     709            float dy = points[i2].y - points[i1].y;
     710            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
     711            temp_normals[i1].x = dy;
     712            temp_normals[i1].y = -dx;
     713        }
     714        if (!closed)
     715            temp_normals[points_count - 1] = temp_normals[points_count - 2];
     716
     717        // If we are drawing a one-pixel-wide line without a texture, or a textured line of any width, we only need 2 or 3 vertices per point
     718        if (use_texture || !thick_line)
     719        {
     720            // [PATH 1] Texture-based lines (thick or non-thick)
     721            // [PATH 2] Non texture-based lines (non-thick)
     722
     723            // The width of the geometry we need to draw - this is essentially <thickness> pixels for the line itself, plus "one pixel" for AA.
     724            // - In the texture-based path, we don't use AA_SIZE here because the +1 is tied to the generated texture
     725            //   (see ImFontAtlasBuildRenderLinesTexData() function), and so alternate values won't work without changes to that code.
     726            // - In the non texture-based paths, we would allow AA_SIZE to potentially be != 1.0f with a patch (e.g. fringe_scale patch to
     727            //   allow scaling geometry while preserving one-screen-pixel AA fringe).
     728            const float half_draw_size = use_texture ? ((thickness * 0.5f) + 1) : AA_SIZE;
     729
     730            // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
     731            if (!closed)
     732            {
     733                temp_points[0] = points[0] + temp_normals[0] * half_draw_size;
     734                temp_points[1] = points[0] - temp_normals[0] * half_draw_size;
     735                temp_points[(points_count-1)*2+0] = points[points_count-1] + temp_normals[points_count-1] * half_draw_size;
     736                temp_points[(points_count-1)*2+1] = points[points_count-1] - temp_normals[points_count-1] * half_draw_size;
     737            }
     738
     739            // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
     740            // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps)
     741            // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
     742            unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
     743            for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
     744            {
     745                const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1; // i2 is the second point of the line segment
     746                const unsigned int idx2 = ((i1 + 1) == points_count) ? _VtxCurrentIdx : (idx1 + (use_texture ? 2 : 3)); // Vertex index for end of segment
     747
     748                // Average normals
     749                float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
     750                float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
     751                IM_FIXNORMAL2F(dm_x, dm_y);
     752                dm_x *= half_draw_size; // dm_x, dm_y are offset to the outer edge of the AA area
     753                dm_y *= half_draw_size;
     754
     755                // Add temporary vertexes for the outer edges
     756                ImVec2* out_vtx = &temp_points[i2 * 2];
     757                out_vtx[0].x = points[i2].x + dm_x;
     758                out_vtx[0].y = points[i2].y + dm_y;
     759                out_vtx[1].x = points[i2].x - dm_x;
     760                out_vtx[1].y = points[i2].y - dm_y;
     761
     762                if (use_texture)
     763                {
     764                    // Add indices for two triangles
     765                    _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 1); // Right tri
     766                    _IdxWritePtr[3] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[4] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Left tri
     767                    _IdxWritePtr += 6;
     768                }
     769                else
     770                {
     771                    // Add indexes for four triangles
     772                    _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2); // Right tri 1
     773                    _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0); // Right tri 2
     774                    _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0); // Left tri 1
     775                    _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1); // Left tri 2
     776                    _IdxWritePtr += 12;
     777                }
     778
     779                idx1 = idx2;
     780            }
     781
     782            // Add vertexes for each point on the line
     783            if (use_texture)
     784            {
     785                // If we're using textures we only need to emit the left/right edge vertices
     786                ImVec4 tex_uvs = _Data->TexUvLines[integer_thickness];
     787                if (fractional_thickness != 0.0f)
     788                {
     789                    const ImVec4 tex_uvs_1 = _Data->TexUvLines[integer_thickness + 1];
     790                    tex_uvs.x = tex_uvs.x + (tex_uvs_1.x - tex_uvs.x) * fractional_thickness; // inlined ImLerp()
     791                    tex_uvs.y = tex_uvs.y + (tex_uvs_1.y - tex_uvs.y) * fractional_thickness;
     792                    tex_uvs.z = tex_uvs.z + (tex_uvs_1.z - tex_uvs.z) * fractional_thickness;
     793                    tex_uvs.w = tex_uvs.w + (tex_uvs_1.w - tex_uvs.w) * fractional_thickness;
     794                }
     795                ImVec2 tex_uv0(tex_uvs.x, tex_uvs.y);
     796                ImVec2 tex_uv1(tex_uvs.z, tex_uvs.w);
     797                for (int i = 0; i < points_count; i++)
     798                {
     799                    _VtxWritePtr[0].pos = temp_points[i * 2 + 0]; _VtxWritePtr[0].uv = tex_uv0; _VtxWritePtr[0].col = col; // Left-side outer edge
     800                    _VtxWritePtr[1].pos = temp_points[i * 2 + 1]; _VtxWritePtr[1].uv = tex_uv1; _VtxWritePtr[1].col = col; // Right-side outer edge
     801                    _VtxWritePtr += 2;
     802                }
     803            }
     804            else
     805            {
     806                // If we're not using a texture, we need the center vertex as well
     807                for (int i = 0; i < points_count; i++)
     808                {
     809                    _VtxWritePtr[0].pos = points[i];              _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;       // Center of line
     810                    _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col_trans; // Left-side outer edge
     811                    _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col_trans; // Right-side outer edge
     812                    _VtxWritePtr += 3;
     813                }
     814            }
     815        }
     816        else
     817        {
     818            // [PATH 2] Non texture-based lines (thick): we need to draw the solid line core and thus require four vertices per point
     819            const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
     820
     821            // If line is not closed, the first and last points need to be generated differently as there are no normals to blend
     822            if (!closed)
     823            {
     824                const int points_last = points_count - 1;
     825                temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
     826                temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
     827                temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
     828                temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
     829                temp_points[points_last * 4 + 0] = points[points_last] + temp_normals[points_last] * (half_inner_thickness + AA_SIZE);
     830                temp_points[points_last * 4 + 1] = points[points_last] + temp_normals[points_last] * (half_inner_thickness);
     831                temp_points[points_last * 4 + 2] = points[points_last] - temp_normals[points_last] * (half_inner_thickness);
     832                temp_points[points_last * 4 + 3] = points[points_last] - temp_normals[points_last] * (half_inner_thickness + AA_SIZE);
     833            }
     834
     835            // Generate the indices to form a number of triangles for each line segment, and the vertices for the line edges
     836            // This takes points n and n+1 and writes into n+1, with the first point in a closed line being generated from the final one (as n+1 wraps)
     837            // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
     838            unsigned int idx1 = _VtxCurrentIdx; // Vertex index for start of line segment
     839            for (int i1 = 0; i1 < count; i1++) // i1 is the first point of the line segment
     840            {
     841                const int i2 = (i1 + 1) == points_count ? 0 : (i1 + 1); // i2 is the second point of the line segment
     842                const unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : (idx1 + 4); // Vertex index for end of segment
     843
     844                // Average normals
     845                float dm_x = (temp_normals[i1].x + temp_normals[i2].x) * 0.5f;
     846                float dm_y = (temp_normals[i1].y + temp_normals[i2].y) * 0.5f;
     847                IM_FIXNORMAL2F(dm_x, dm_y);
     848                float dm_out_x = dm_x * (half_inner_thickness + AA_SIZE);
     849                float dm_out_y = dm_y * (half_inner_thickness + AA_SIZE);
     850                float dm_in_x = dm_x * half_inner_thickness;
     851                float dm_in_y = dm_y * half_inner_thickness;
     852
     853                // Add temporary vertices
     854                ImVec2* out_vtx = &temp_points[i2 * 4];
     855                out_vtx[0].x = points[i2].x + dm_out_x;
     856                out_vtx[0].y = points[i2].y + dm_out_y;
     857                out_vtx[1].x = points[i2].x + dm_in_x;
     858                out_vtx[1].y = points[i2].y + dm_in_y;
     859                out_vtx[2].x = points[i2].x - dm_in_x;
     860                out_vtx[2].y = points[i2].y - dm_in_y;
     861                out_vtx[3].x = points[i2].x - dm_out_x;
     862                out_vtx[3].y = points[i2].y - dm_out_y;
     863
     864                // Add indexes
     865                _IdxWritePtr[0]  = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1]  = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2]  = (ImDrawIdx)(idx1 + 2);
     866                _IdxWritePtr[3]  = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4]  = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5]  = (ImDrawIdx)(idx2 + 1);
     867                _IdxWritePtr[6]  = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7]  = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8]  = (ImDrawIdx)(idx1 + 0);
     868                _IdxWritePtr[9]  = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
     869                _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3);
     870                _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2);
     871                _IdxWritePtr += 18;
     872
     873                idx1 = idx2;
     874            }
     875
     876            // Add vertices
     877            for (int i = 0; i < points_count; i++)
     878            {
     879                _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col_trans;
     880                _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;
     881                _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;
     882                _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col_trans;
     883                _VtxWritePtr += 4;
     884            }
     885        }
     886        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
     887    }
     888    else
     889    {
     890        // [PATH 4] Non texture-based, Non anti-aliased lines
     891        const int idx_count = count * 6;
     892        const int vtx_count = count * 4;    // FIXME-OPT: Not sharing edges
     893        PrimReserve(idx_count, vtx_count);
     894
     895        for (int i1 = 0; i1 < count; i1++)
     896        {
     897            const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
     898            const ImVec2& p1 = points[i1];
     899            const ImVec2& p2 = points[i2];
     900
     901            float dx = p2.x - p1.x;
     902            float dy = p2.y - p1.y;
     903            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
     904            dx *= (thickness * 0.5f);
     905            dy *= (thickness * 0.5f);
     906
     907            _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = opaque_uv; _VtxWritePtr[0].col = col;
     908            _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = opaque_uv; _VtxWritePtr[1].col = col;
     909            _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = opaque_uv; _VtxWritePtr[2].col = col;
     910            _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = opaque_uv; _VtxWritePtr[3].col = col;
     911            _VtxWritePtr += 4;
     912
     913            _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2);
     914            _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3);
     915            _IdxWritePtr += 6;
     916            _VtxCurrentIdx += 4;
     917        }
     918    }
     919}
     920
     921// We intentionally avoid using ImVec2 and its math operators here to reduce cost to a minimum for debug/non-inlined builds.
     922void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
     923{
     924    if (points_count < 3)
     925        return;
     926
     927    const ImVec2 uv = _Data->TexUvWhitePixel;
     928
     929    if (Flags & ImDrawListFlags_AntiAliasedFill)
     930    {
     931        // Anti-aliased Fill
     932        const float AA_SIZE = 1.0f;
     933        const ImU32 col_trans = col & ~IM_COL32_A_MASK;
     934        const int idx_count = (points_count - 2)*3 + points_count * 6;
     935        const int vtx_count = (points_count * 2);
     936        PrimReserve(idx_count, vtx_count);
     937
     938        // Add indexes for fill
     939        unsigned int vtx_inner_idx = _VtxCurrentIdx;
     940        unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
     941        for (int i = 2; i < points_count; i++)
     942        {
     943            _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1));
     944            _IdxWritePtr += 3;
     945        }
     946
     947        // Compute normals
     948        ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2)); //-V630
     949        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
     950        {
     951            const ImVec2& p0 = points[i0];
     952            const ImVec2& p1 = points[i1];
     953            float dx = p1.x - p0.x;
     954            float dy = p1.y - p0.y;
     955            IM_NORMALIZE2F_OVER_ZERO(dx, dy);
     956            temp_normals[i0].x = dy;
     957            temp_normals[i0].y = -dx;
     958        }
     959
     960        for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
     961        {
    670962            // Average normals
    671             ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
    672             float dmr2 = dm.x*dm.x + dm.y*dm.y;
    673             if (dmr2 > 0.000001f)
     963            const ImVec2& n0 = temp_normals[i0];
     964            const ImVec2& n1 = temp_normals[i1];
     965            float dm_x = (n0.x + n1.x) * 0.5f;
     966            float dm_y = (n0.y + n1.y) * 0.5f;
     967            IM_FIXNORMAL2F(dm_x, dm_y);
     968            dm_x *= AA_SIZE * 0.5f;
     969            dm_y *= AA_SIZE * 0.5f;
     970
     971            // Add vertices
     972            _VtxWritePtr[0].pos.x = (points[i1].x - dm_x); _VtxWritePtr[0].pos.y = (points[i1].y - dm_y); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;        // Inner
     973            _VtxWritePtr[1].pos.x = (points[i1].x + dm_x); _VtxWritePtr[1].pos.y = (points[i1].y + dm_y); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans;  // Outer
     974            _VtxWritePtr += 2;
     975
     976            // Add indexes for fringes
     977            _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
     978            _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
     979            _IdxWritePtr += 6;
     980        }
     981        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
     982    }
     983    else
     984    {
     985        // Non Anti-aliased Fill
     986        const int idx_count = (points_count - 2)*3;
     987        const int vtx_count = points_count;
     988        PrimReserve(idx_count, vtx_count);
     989        for (int i = 0; i < vtx_count; i++)
     990        {
     991            _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
     992            _VtxWritePtr++;
     993        }
     994        for (int i = 2; i < points_count; i++)
     995        {
     996            _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i);
     997            _IdxWritePtr += 3;
     998        }
     999        _VtxCurrentIdx += (ImDrawIdx)vtx_count;
     1000    }
     1001}
     1002
     1003void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12)
     1004{
     1005    if (radius == 0.0f || a_min_of_12 > a_max_of_12)
     1006    {
     1007        _Path.push_back(center);
     1008        return;
     1009    }
     1010
     1011    // For legacy reason the PathArcToFast() always takes angles where 2*PI is represented by 12,
     1012    // but it is possible to set IM_DRAWLIST_ARCFAST_TESSELATION_MULTIPLIER to a higher value. This should compile to a no-op otherwise.
     1013#if IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER != 1
     1014    a_min_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER;
     1015    a_max_of_12 *= IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER;
     1016#endif
     1017
     1018    _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1));
     1019    for (int a = a_min_of_12; a <= a_max_of_12; a++)
     1020    {
     1021        const ImVec2& c = _Data->ArcFastVtx[a % IM_ARRAYSIZE(_Data->ArcFastVtx)];
     1022        _Path.push_back(ImVec2(center.x + c.x * radius, center.y + c.y * radius));
     1023    }
     1024}
     1025
     1026void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
     1027{
     1028    if (radius == 0.0f)
     1029    {
     1030        _Path.push_back(center);
     1031        return;
     1032    }
     1033
     1034    // Note that we are adding a point at both a_min and a_max.
     1035    // If you are trying to draw a full closed circle you don't want the overlapping points!
     1036    _Path.reserve(_Path.Size + (num_segments + 1));
     1037    for (int i = 0; i <= num_segments; i++)
     1038    {
     1039        const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
     1040        _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius));
     1041    }
     1042}
     1043
     1044ImVec2 ImBezierCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)
     1045{
     1046    float u = 1.0f - t;
     1047    float w1 = u*u*u;
     1048    float w2 = 3*u*u*t;
     1049    float w3 = 3*u*t*t;
     1050    float w4 = t*t*t;
     1051    return ImVec2(w1*p1.x + w2*p2.x + w3*p3.x + w4*p4.x, w1*p1.y + w2*p2.y + w3*p3.y + w4*p4.y);
     1052}
     1053
     1054// Closely mimics BezierClosestPointCasteljauStep() in imgui.cpp
     1055static void PathBezierToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
     1056{
     1057    float dx = x4 - x1;
     1058    float dy = y4 - y1;
     1059    float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
     1060    float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
     1061    d2 = (d2 >= 0) ? d2 : -d2;
     1062    d3 = (d3 >= 0) ? d3 : -d3;
     1063    if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
     1064    {
     1065        path->push_back(ImVec2(x4, y4));
     1066    }
     1067    else if (level < 10)
     1068    {
     1069        float x12 = (x1 + x2)*0.5f,       y12 = (y1 + y2)*0.5f;
     1070        float x23 = (x2 + x3)*0.5f,       y23 = (y2 + y3)*0.5f;
     1071        float x34 = (x3 + x4)*0.5f,       y34 = (y3 + y4)*0.5f;
     1072        float x123 = (x12 + x23)*0.5f,    y123 = (y12 + y23)*0.5f;
     1073        float x234 = (x23 + x34)*0.5f,    y234 = (y23 + y34)*0.5f;
     1074        float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
     1075        PathBezierToCasteljau(path, x1, y1,        x12, y12,    x123, y123,  x1234, y1234, tess_tol, level + 1);
     1076        PathBezierToCasteljau(path, x1234, y1234,  x234, y234,  x34, y34,    x4, y4,       tess_tol, level + 1);
     1077    }
     1078}
     1079
     1080void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
     1081{
     1082    ImVec2 p1 = _Path.back();
     1083    if (num_segments == 0)
     1084    {
     1085        PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated
     1086    }
     1087    else
     1088    {
     1089        float t_step = 1.0f / (float)num_segments;
     1090        for (int i_step = 1; i_step <= num_segments; i_step++)
     1091            _Path.push_back(ImBezierCalc(p1, p2, p3, p4, t_step * i_step));
     1092    }
     1093}
     1094
     1095void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawCornerFlags rounding_corners)
     1096{
     1097    rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top)  == ImDrawCornerFlags_Top)  || ((rounding_corners & ImDrawCornerFlags_Bot)   == ImDrawCornerFlags_Bot)   ? 0.5f : 1.0f ) - 1.0f);
     1098    rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f);
     1099
     1100    if (rounding <= 0.0f || rounding_corners == 0)
     1101    {
     1102        PathLineTo(a);
     1103        PathLineTo(ImVec2(b.x, a.y));
     1104        PathLineTo(b);
     1105        PathLineTo(ImVec2(a.x, b.y));
     1106    }
     1107    else
     1108    {
     1109        const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f;
     1110        const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f;
     1111        const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f;
     1112        const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f;
     1113        PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);
     1114        PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);
     1115        PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);
     1116        PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);
     1117    }
     1118}
     1119
     1120void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness)
     1121{
     1122    if ((col & IM_COL32_A_MASK) == 0)
     1123        return;
     1124    PathLineTo(p1 + ImVec2(0.5f, 0.5f));
     1125    PathLineTo(p2 + ImVec2(0.5f, 0.5f));
     1126    PathStroke(col, false, thickness);
     1127}
     1128
     1129// p_min = upper-left, p_max = lower-right
     1130// Note we don't render 1 pixels sized rectangles properly.
     1131void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners, float thickness)
     1132{
     1133    if ((col & IM_COL32_A_MASK) == 0)
     1134        return;
     1135    if (Flags & ImDrawListFlags_AntiAliasedLines)
     1136        PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.50f, 0.50f), rounding, rounding_corners);
     1137    else
     1138        PathRect(p_min + ImVec2(0.50f, 0.50f), p_max - ImVec2(0.49f, 0.49f), rounding, rounding_corners); // Better looking lower-right corner and rounded non-AA shapes.
     1139    PathStroke(col, true, thickness);
     1140}
     1141
     1142void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners)
     1143{
     1144    if ((col & IM_COL32_A_MASK) == 0)
     1145        return;
     1146    if (rounding > 0.0f)
     1147    {
     1148        PathRect(p_min, p_max, rounding, rounding_corners);
     1149        PathFillConvex(col);
     1150    }
     1151    else
     1152    {
     1153        PrimReserve(6, 4);
     1154        PrimRect(p_min, p_max, col);
     1155    }
     1156}
     1157
     1158// p_min = upper-left, p_max = lower-right
     1159void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
     1160{
     1161    if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
     1162        return;
     1163
     1164    const ImVec2 uv = _Data->TexUvWhitePixel;
     1165    PrimReserve(6, 4);
     1166    PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));
     1167    PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3));
     1168    PrimWriteVtx(p_min, uv, col_upr_left);
     1169    PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right);
     1170    PrimWriteVtx(p_max, uv, col_bot_right);
     1171    PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left);
     1172}
     1173
     1174void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness)
     1175{
     1176    if ((col & IM_COL32_A_MASK) == 0)
     1177        return;
     1178
     1179    PathLineTo(p1);
     1180    PathLineTo(p2);
     1181    PathLineTo(p3);
     1182    PathLineTo(p4);
     1183    PathStroke(col, true, thickness);
     1184}
     1185
     1186void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col)
     1187{
     1188    if ((col & IM_COL32_A_MASK) == 0)
     1189        return;
     1190
     1191    PathLineTo(p1);
     1192    PathLineTo(p2);
     1193    PathLineTo(p3);
     1194    PathLineTo(p4);
     1195    PathFillConvex(col);
     1196}
     1197
     1198void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness)
     1199{
     1200    if ((col & IM_COL32_A_MASK) == 0)
     1201        return;
     1202
     1203    PathLineTo(p1);
     1204    PathLineTo(p2);
     1205    PathLineTo(p3);
     1206    PathStroke(col, true, thickness);
     1207}
     1208
     1209void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col)
     1210{
     1211    if ((col & IM_COL32_A_MASK) == 0)
     1212        return;
     1213
     1214    PathLineTo(p1);
     1215    PathLineTo(p2);
     1216    PathLineTo(p3);
     1217    PathFillConvex(col);
     1218}
     1219
     1220void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
     1221{
     1222    if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
     1223        return;
     1224
     1225    // Obtain segment count
     1226    if (num_segments <= 0)
     1227    {
     1228        // Automatic segment count
     1229        const int radius_idx = (int)radius - 1;
     1230        if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
     1231            num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value
     1232        else
     1233            num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
     1234    }
     1235    else
     1236    {
     1237        // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
     1238        num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
     1239    }
     1240
     1241    // Because we are filling a closed shape we remove 1 from the count of segments/points
     1242    const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
     1243    if (num_segments == 12)
     1244        PathArcToFast(center, radius - 0.5f, 0, 12 - 1);
     1245    else
     1246        PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
     1247    PathStroke(col, true, thickness);
     1248}
     1249
     1250void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
     1251{
     1252    if ((col & IM_COL32_A_MASK) == 0 || radius <= 0.0f)
     1253        return;
     1254
     1255    // Obtain segment count
     1256    if (num_segments <= 0)
     1257    {
     1258        // Automatic segment count
     1259        const int radius_idx = (int)radius - 1;
     1260        if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
     1261            num_segments = _Data->CircleSegmentCounts[radius_idx]; // Use cached value
     1262        else
     1263            num_segments = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
     1264    }
     1265    else
     1266    {
     1267        // Explicit segment count (still clamp to avoid drawing insanely tessellated shapes)
     1268        num_segments = ImClamp(num_segments, 3, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX);
     1269    }
     1270
     1271    // Because we are filling a closed shape we remove 1 from the count of segments/points
     1272    const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
     1273    if (num_segments == 12)
     1274        PathArcToFast(center, radius, 0, 12 - 1);
     1275    else
     1276        PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
     1277    PathFillConvex(col);
     1278}
     1279
     1280// Guaranteed to honor 'num_segments'
     1281void ImDrawList::AddNgon(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
     1282{
     1283    if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
     1284        return;
     1285
     1286    // Because we are filling a closed shape we remove 1 from the count of segments/points
     1287    const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
     1288    PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
     1289    PathStroke(col, true, thickness);
     1290}
     1291
     1292// Guaranteed to honor 'num_segments'
     1293void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
     1294{
     1295    if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
     1296        return;
     1297
     1298    // Because we are filling a closed shape we remove 1 from the count of segments/points
     1299    const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
     1300    PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
     1301    PathFillConvex(col);
     1302}
     1303
     1304// Cubic Bezier takes 4 controls points
     1305void ImDrawList::AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments)
     1306{
     1307    if ((col & IM_COL32_A_MASK) == 0)
     1308        return;
     1309
     1310    PathLineTo(p1);
     1311    PathBezierCurveTo(p2, p3, p4, num_segments);
     1312    PathStroke(col, false, thickness);
     1313}
     1314
     1315void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
     1316{
     1317    if ((col & IM_COL32_A_MASK) == 0)
     1318        return;
     1319
     1320    if (text_end == NULL)
     1321        text_end = text_begin + strlen(text_begin);
     1322    if (text_begin == text_end)
     1323        return;
     1324
     1325    // Pull default font/size from the shared ImDrawListSharedData instance
     1326    if (font == NULL)
     1327        font = _Data->Font;
     1328    if (font_size == 0.0f)
     1329        font_size = _Data->FontSize;
     1330
     1331    IM_ASSERT(font->ContainerAtlas->TexID == _CmdHeader.TextureId);  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
     1332
     1333    ImVec4 clip_rect = _CmdHeader.ClipRect;
     1334    if (cpu_fine_clip_rect)
     1335    {
     1336        clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
     1337        clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
     1338        clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
     1339        clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
     1340    }
     1341    font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
     1342}
     1343
     1344void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
     1345{
     1346    AddText(NULL, 0.0f, pos, col, text_begin, text_end);
     1347}
     1348
     1349void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col)
     1350{
     1351    if ((col & IM_COL32_A_MASK) == 0)
     1352        return;
     1353
     1354    const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
     1355    if (push_texture_id)
     1356        PushTextureID(user_texture_id);
     1357
     1358    PrimReserve(6, 4);
     1359    PrimRectUV(p_min, p_max, uv_min, uv_max, col);
     1360
     1361    if (push_texture_id)
     1362        PopTextureID();
     1363}
     1364
     1365void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col)
     1366{
     1367    if ((col & IM_COL32_A_MASK) == 0)
     1368        return;
     1369
     1370    const bool push_texture_id = user_texture_id != _CmdHeader.TextureId;
     1371    if (push_texture_id)
     1372        PushTextureID(user_texture_id);
     1373
     1374    PrimReserve(6, 4);
     1375    PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col);
     1376
     1377    if (push_texture_id)
     1378        PopTextureID();
     1379}
     1380
     1381void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners)
     1382{
     1383    if ((col & IM_COL32_A_MASK) == 0)
     1384        return;
     1385
     1386    if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0)
     1387    {
     1388        AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col);
     1389        return;
     1390    }
     1391
     1392    const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
     1393    if (push_texture_id)
     1394        PushTextureID(user_texture_id);
     1395
     1396    int vert_start_idx = VtxBuffer.Size;
     1397    PathRect(p_min, p_max, rounding, rounding_corners);
     1398    PathFillConvex(col);
     1399    int vert_end_idx = VtxBuffer.Size;
     1400    ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true);
     1401
     1402    if (push_texture_id)
     1403        PopTextureID();
     1404}
     1405
     1406
     1407//-----------------------------------------------------------------------------
     1408// [SECTION] ImDrawListSplitter
     1409//-----------------------------------------------------------------------------
     1410// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap..
     1411//-----------------------------------------------------------------------------
     1412
     1413void ImDrawListSplitter::ClearFreeMemory()
     1414{
     1415    for (int i = 0; i < _Channels.Size; i++)
     1416    {
     1417        if (i == _Current)
     1418            memset(&_Channels[i], 0, sizeof(_Channels[i]));  // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again
     1419        _Channels[i]._CmdBuffer.clear();
     1420        _Channels[i]._IdxBuffer.clear();
     1421    }
     1422    _Current = 0;
     1423    _Count = 1;
     1424    _Channels.clear();
     1425}
     1426
     1427void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count)
     1428{
     1429    IM_ASSERT(_Current == 0 && _Count <= 1 && "Nested channel splitting is not supported. Please use separate instances of ImDrawListSplitter.");
     1430    int old_channels_count = _Channels.Size;
     1431    if (old_channels_count < channels_count)
     1432        _Channels.resize(channels_count);
     1433    _Count = channels_count;
     1434
     1435    // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer
     1436    // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to.
     1437    // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer
     1438    memset(&_Channels[0], 0, sizeof(ImDrawChannel));
     1439    for (int i = 1; i < channels_count; i++)
     1440    {
     1441        if (i >= old_channels_count)
     1442        {
     1443            IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
     1444        }
     1445        else
     1446        {
     1447            _Channels[i]._CmdBuffer.resize(0);
     1448            _Channels[i]._IdxBuffer.resize(0);
     1449        }
     1450        if (_Channels[i]._CmdBuffer.Size == 0)
     1451        {
     1452            ImDrawCmd draw_cmd;
     1453            ImDrawCmd_HeaderCopy(&draw_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
     1454            _Channels[i]._CmdBuffer.push_back(draw_cmd);
     1455        }
     1456    }
     1457}
     1458
     1459void ImDrawListSplitter::Merge(ImDrawList* draw_list)
     1460{
     1461    // Note that we never use or rely on _Channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
     1462    if (_Count <= 1)
     1463        return;
     1464
     1465    SetCurrentChannel(draw_list, 0);
     1466    draw_list->_PopUnusedDrawCmd();
     1467
     1468    // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.
     1469    int new_cmd_buffer_count = 0;
     1470    int new_idx_buffer_count = 0;
     1471    ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL;
     1472    int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0;
     1473    for (int i = 1; i < _Count; i++)
     1474    {
     1475        ImDrawChannel& ch = _Channels[i];
     1476
     1477        // Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback.
     1478        if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0)
     1479            ch._CmdBuffer.pop_back();
     1480
     1481        if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
     1482        {
     1483            ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
     1484            if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
    6741485            {
    675                float scale = 1.0f / dmr2;
    676                if (scale > 100.0f) scale = 100.0f;
    677                dm *= scale;
     1486                // Merge previous channel last draw command with current channel first draw command if matching.
     1487                last_cmd->ElemCount += next_cmd->ElemCount;
     1488                idx_offset += next_cmd->ElemCount;
     1489                ch._CmdBuffer.erase(ch._CmdBuffer.Data); // FIXME-OPT: Improve for multiple merges.
    6781490            }
    679             dm *= AA_SIZE;
    680             temp_points[i2 * 2 + 0] = points[i2] + dm;
    681             temp_points[i2 * 2 + 1] = points[i2] - dm;
    682 
    683             // Add indexes
    684             _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2);
    685             _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 0);
    686             _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0);
    687             _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
    688             _IdxWritePtr += 12;
    689 
    690             idx1 = idx2;
    691          }
    692 
    693          // Add vertexes
    694          for (int i = 0; i < points_count; i++)
    695          {
    696             _VtxWritePtr[0].pos = points[i];          _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
    697             _VtxWritePtr[1].pos = temp_points[i * 2 + 0]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans;
    698             _VtxWritePtr[2].pos = temp_points[i * 2 + 1]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col_trans;
    699             _VtxWritePtr += 3;
    700          }
    701       }
    702       else
    703       {
    704          const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;
    705          if (!closed)
    706          {
    707             temp_points[0] = points[0] + temp_normals[0] * (half_inner_thickness + AA_SIZE);
    708             temp_points[1] = points[0] + temp_normals[0] * (half_inner_thickness);
    709             temp_points[2] = points[0] - temp_normals[0] * (half_inner_thickness);
    710             temp_points[3] = points[0] - temp_normals[0] * (half_inner_thickness + AA_SIZE);
    711             temp_points[(points_count - 1) * 4 + 0] = points[points_count - 1] + temp_normals[points_count - 1] * (half_inner_thickness + AA_SIZE);
    712             temp_points[(points_count - 1) * 4 + 1] = points[points_count - 1] + temp_normals[points_count - 1] * (half_inner_thickness);
    713             temp_points[(points_count - 1) * 4 + 2] = points[points_count - 1] - temp_normals[points_count - 1] * (half_inner_thickness);
    714             temp_points[(points_count - 1) * 4 + 3] = points[points_count - 1] - temp_normals[points_count - 1] * (half_inner_thickness + AA_SIZE);
    715          }
    716 
    717          // FIXME-OPT: Merge the different loops, possibly remove the temporary buffer.
    718          unsigned int idx1 = _VtxCurrentIdx;
    719          for (int i1 = 0; i1 < count; i1++)
    720          {
    721             const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
    722             unsigned int idx2 = (i1 + 1) == points_count ? _VtxCurrentIdx : idx1 + 4;
    723 
    724             // Average normals
    725             ImVec2 dm = (temp_normals[i1] + temp_normals[i2]) * 0.5f;
    726             float dmr2 = dm.x*dm.x + dm.y*dm.y;
    727             if (dmr2 > 0.000001f)
    728             {
    729                float scale = 1.0f / dmr2;
    730                if (scale > 100.0f) scale = 100.0f;
    731                dm *= scale;
    732             }
    733             ImVec2 dm_out = dm * (half_inner_thickness + AA_SIZE);
    734             ImVec2 dm_in = dm * half_inner_thickness;
    735             temp_points[i2 * 4 + 0] = points[i2] + dm_out;
    736             temp_points[i2 * 4 + 1] = points[i2] + dm_in;
    737             temp_points[i2 * 4 + 2] = points[i2] - dm_in;
    738             temp_points[i2 * 4 + 3] = points[i2] - dm_out;
    739 
    740             // Add indexes
    741             _IdxWritePtr[0] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[1] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[2] = (ImDrawIdx)(idx1 + 2);
    742             _IdxWritePtr[3] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[4] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[5] = (ImDrawIdx)(idx2 + 1);
    743             _IdxWritePtr[6] = (ImDrawIdx)(idx2 + 1); _IdxWritePtr[7] = (ImDrawIdx)(idx1 + 1); _IdxWritePtr[8] = (ImDrawIdx)(idx1 + 0);
    744             _IdxWritePtr[9] = (ImDrawIdx)(idx1 + 0); _IdxWritePtr[10] = (ImDrawIdx)(idx2 + 0); _IdxWritePtr[11] = (ImDrawIdx)(idx2 + 1);
    745             _IdxWritePtr[12] = (ImDrawIdx)(idx2 + 2); _IdxWritePtr[13] = (ImDrawIdx)(idx1 + 2); _IdxWritePtr[14] = (ImDrawIdx)(idx1 + 3);
    746             _IdxWritePtr[15] = (ImDrawIdx)(idx1 + 3); _IdxWritePtr[16] = (ImDrawIdx)(idx2 + 3); _IdxWritePtr[17] = (ImDrawIdx)(idx2 + 2);
    747             _IdxWritePtr += 18;
    748 
    749             idx1 = idx2;
    750          }
    751 
    752          // Add vertexes
    753          for (int i = 0; i < points_count; i++)
    754          {
    755             _VtxWritePtr[0].pos = temp_points[i * 4 + 0]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col_trans;
    756             _VtxWritePtr[1].pos = temp_points[i * 4 + 1]; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
    757             _VtxWritePtr[2].pos = temp_points[i * 4 + 2]; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
    758             _VtxWritePtr[3].pos = temp_points[i * 4 + 3]; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col_trans;
    759             _VtxWritePtr += 4;
    760          }
    761       }
    762       _VtxCurrentIdx += (ImDrawIdx)vtx_count;
    763    }
    764    else
    765    {
    766       // Non Anti-aliased Stroke
    767       const int idx_count = count * 6;
    768       const int vtx_count = count * 4;      // FIXME-OPT: Not sharing edges
    769       PrimReserve(idx_count, vtx_count);
    770 
    771       for (int i1 = 0; i1 < count; i1++)
    772       {
    773          const int i2 = (i1 + 1) == points_count ? 0 : i1 + 1;
    774          const ImVec2& p1 = points[i1];
    775          const ImVec2& p2 = points[i2];
    776          ImVec2 diff = p2 - p1;
    777          diff *= ImInvLength(diff, 1.0f);
    778 
    779          const float dx = diff.x * (thickness * 0.5f);
    780          const float dy = diff.y * (thickness * 0.5f);
    781          _VtxWritePtr[0].pos.x = p1.x + dy; _VtxWritePtr[0].pos.y = p1.y - dx; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
    782          _VtxWritePtr[1].pos.x = p2.x + dy; _VtxWritePtr[1].pos.y = p2.y - dx; _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col;
    783          _VtxWritePtr[2].pos.x = p2.x - dy; _VtxWritePtr[2].pos.y = p2.y + dx; _VtxWritePtr[2].uv = uv; _VtxWritePtr[2].col = col;
    784          _VtxWritePtr[3].pos.x = p1.x - dy; _VtxWritePtr[3].pos.y = p1.y + dx; _VtxWritePtr[3].uv = uv; _VtxWritePtr[3].col = col;
    785          _VtxWritePtr += 4;
    786 
    787          _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + 2);
    788          _IdxWritePtr[3] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[4] = (ImDrawIdx)(_VtxCurrentIdx + 2); _IdxWritePtr[5] = (ImDrawIdx)(_VtxCurrentIdx + 3);
    789          _IdxWritePtr += 6;
    790          _VtxCurrentIdx += 4;
    791       }
    792    }
    793 }
    794 
    795 void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
    796 {
    797    const ImVec2 uv = _Data->TexUvWhitePixel;
    798 
    799    if (Flags & ImDrawListFlags_AntiAliasedFill)
    800    {
    801       // Anti-aliased Fill
    802       const float AA_SIZE = 1.0f;
    803       const ImU32 col_trans = col & ~IM_COL32_A_MASK;
    804       const int idx_count = (points_count - 2) * 3 + points_count * 6;
    805       const int vtx_count = (points_count * 2);
    806       PrimReserve(idx_count, vtx_count);
    807 
    808       // Add indexes for fill
    809       unsigned int vtx_inner_idx = _VtxCurrentIdx;
    810       unsigned int vtx_outer_idx = _VtxCurrentIdx + 1;
    811       for (int i = 2; i < points_count; i++)
    812       {
    813          _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + ((i - 1) << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_inner_idx + (i << 1));
    814          _IdxWritePtr += 3;
    815       }
    816 
    817       // Compute normals
    818       ImVec2* temp_normals = (ImVec2*)alloca(points_count * sizeof(ImVec2));
    819       for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
    820       {
    821          const ImVec2& p0 = points[i0];
    822          const ImVec2& p1 = points[i1];
    823          ImVec2 diff = p1 - p0;
    824          diff *= ImInvLength(diff, 1.0f);
    825          temp_normals[i0].x = diff.y;
    826          temp_normals[i0].y = -diff.x;
    827       }
    828 
    829       for (int i0 = points_count - 1, i1 = 0; i1 < points_count; i0 = i1++)
    830       {
    831          // Average normals
    832          const ImVec2& n0 = temp_normals[i0];
    833          const ImVec2& n1 = temp_normals[i1];
    834          ImVec2 dm = (n0 + n1) * 0.5f;
    835          float dmr2 = dm.x*dm.x + dm.y*dm.y;
    836          if (dmr2 > 0.000001f)
    837          {
    838             float scale = 1.0f / dmr2;
    839             if (scale > 100.0f) scale = 100.0f;
    840             dm *= scale;
    841          }
    842          dm *= AA_SIZE * 0.5f;
    843 
    844          // Add vertices
    845          _VtxWritePtr[0].pos = (points[i1] - dm); _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;        // Inner
    846          _VtxWritePtr[1].pos = (points[i1] + dm); _VtxWritePtr[1].uv = uv; _VtxWritePtr[1].col = col_trans;  // Outer
    847          _VtxWritePtr += 2;
    848 
    849          // Add indexes for fringes
    850          _IdxWritePtr[0] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1)); _IdxWritePtr[1] = (ImDrawIdx)(vtx_inner_idx + (i0 << 1)); _IdxWritePtr[2] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1));
    851          _IdxWritePtr[3] = (ImDrawIdx)(vtx_outer_idx + (i0 << 1)); _IdxWritePtr[4] = (ImDrawIdx)(vtx_outer_idx + (i1 << 1)); _IdxWritePtr[5] = (ImDrawIdx)(vtx_inner_idx + (i1 << 1));
    852          _IdxWritePtr += 6;
    853       }
    854       _VtxCurrentIdx += (ImDrawIdx)vtx_count;
    855    }
    856    else
    857    {
    858       // Non Anti-aliased Fill
    859       const int idx_count = (points_count - 2) * 3;
    860       const int vtx_count = points_count;
    861       PrimReserve(idx_count, vtx_count);
    862       for (int i = 0; i < vtx_count; i++)
    863       {
    864          _VtxWritePtr[0].pos = points[i]; _VtxWritePtr[0].uv = uv; _VtxWritePtr[0].col = col;
    865          _VtxWritePtr++;
    866       }
    867       for (int i = 2; i < points_count; i++)
    868       {
    869          _IdxWritePtr[0] = (ImDrawIdx)(_VtxCurrentIdx); _IdxWritePtr[1] = (ImDrawIdx)(_VtxCurrentIdx + i - 1); _IdxWritePtr[2] = (ImDrawIdx)(_VtxCurrentIdx + i);
    870          _IdxWritePtr += 3;
    871       }
    872       _VtxCurrentIdx += (ImDrawIdx)vtx_count;
    873    }
    874 }
    875 
    876 void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12)
    877 {
    878    if (radius == 0.0f || a_min_of_12 > a_max_of_12)
    879    {
    880       _Path.push_back(centre);
    881       return;
    882    }
    883    _Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1));
    884    for (int a = a_min_of_12; a <= a_max_of_12; a++)
    885    {
    886       const ImVec2& c = _Data->CircleVtx12[a % IM_ARRAYSIZE(_Data->CircleVtx12)];
    887       _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius));
    888    }
    889 }
    890 
    891 void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments)
    892 {
    893    if (radius == 0.0f)
    894    {
    895       _Path.push_back(centre);
    896       return;
    897    }
    898    _Path.reserve(_Path.Size + (num_segments + 1));
    899    for (int i = 0; i <= num_segments; i++)
    900    {
    901       const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
    902       _Path.push_back(ImVec2(centre.x + cosf(a) * radius, centre.y + sinf(a) * radius));
    903    }
    904 }
    905 
    906 static void PathBezierToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
    907 {
    908    float dx = x4 - x1;
    909    float dy = y4 - y1;
    910    float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
    911    float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
    912    d2 = (d2 >= 0) ? d2 : -d2;
    913    d3 = (d3 >= 0) ? d3 : -d3;
    914    if ((d2 + d3) * (d2 + d3) < tess_tol * (dx*dx + dy * dy))
    915    {
    916       path->push_back(ImVec2(x4, y4));
    917    }
    918    else if (level < 10)
    919    {
    920       float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
    921       float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
    922       float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
    923       float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
    924       float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
    925       float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
    926 
    927       PathBezierToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
    928       PathBezierToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
    929    }
    930 }
    931 
    932 void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
    933 {
    934    ImVec2 p1 = _Path.back();
    935    if (num_segments == 0)
    936    {
    937       // Auto-tessellated
    938       PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0);
    939    }
    940    else
    941    {
    942       float t_step = 1.0f / (float)num_segments;
    943       for (int i_step = 1; i_step <= num_segments; i_step++)
    944       {
    945          float t = t_step * i_step;
    946          float u = 1.0f - t;
    947          float w1 = u * u*u;
    948          float w2 = 3 * u*u*t;
    949          float w3 = 3 * u*t*t;
    950          float w4 = t * t*t;
    951          _Path.push_back(ImVec2(w1*p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1*p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y));
    952       }
    953    }
    954 }
    955 
    956 void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners)
    957 {
    958    rounding = ImMin(rounding, fabsf(b.x - a.x) * (((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f) - 1.0f);
    959    rounding = ImMin(rounding, fabsf(b.y - a.y) * (((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f) - 1.0f);
    960 
    961    if (rounding <= 0.0f || rounding_corners == 0)
    962    {
    963       PathLineTo(a);
    964       PathLineTo(ImVec2(b.x, a.y));
    965       PathLineTo(b);
    966       PathLineTo(ImVec2(a.x, b.y));
    967    }
    968    else
    969    {
    970       const float rounding_tl = (rounding_corners & ImDrawCornerFlags_TopLeft) ? rounding : 0.0f;
    971       const float rounding_tr = (rounding_corners & ImDrawCornerFlags_TopRight) ? rounding : 0.0f;
    972       const float rounding_br = (rounding_corners & ImDrawCornerFlags_BotRight) ? rounding : 0.0f;
    973       const float rounding_bl = (rounding_corners & ImDrawCornerFlags_BotLeft) ? rounding : 0.0f;
    974       PathArcToFast(ImVec2(a.x + rounding_tl, a.y + rounding_tl), rounding_tl, 6, 9);
    975       PathArcToFast(ImVec2(b.x - rounding_tr, a.y + rounding_tr), rounding_tr, 9, 12);
    976       PathArcToFast(ImVec2(b.x - rounding_br, b.y - rounding_br), rounding_br, 0, 3);
    977       PathArcToFast(ImVec2(a.x + rounding_bl, b.y - rounding_bl), rounding_bl, 3, 6);
    978    }
    979 }
    980 
    981 void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness)
    982 {
    983    if ((col & IM_COL32_A_MASK) == 0)
    984       return;
    985    PathLineTo(a + ImVec2(0.5f, 0.5f));
    986    PathLineTo(b + ImVec2(0.5f, 0.5f));
    987    PathStroke(col, false, thickness);
    988 }
    989 
    990 // a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly.
    991 void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness)
    992 {
    993    if ((col & IM_COL32_A_MASK) == 0)
    994       return;
    995    if (Flags & ImDrawListFlags_AntiAliasedLines)
    996       PathRect(a + ImVec2(0.5f, 0.5f), b - ImVec2(0.50f, 0.50f), rounding, rounding_corners_flags);
    997    else
    998       PathRect(a + ImVec2(0.5f, 0.5f), b - ImVec2(0.49f, 0.49f), rounding, rounding_corners_flags); // Better looking lower-right corner and rounded non-AA shapes.
    999    PathStroke(col, true, thickness);
    1000 }
    1001 
    1002 void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags)
    1003 {
    1004    if ((col & IM_COL32_A_MASK) == 0)
    1005       return;
    1006    if (rounding > 0.0f)
    1007    {
    1008       PathRect(a, b, rounding, rounding_corners_flags);
    1009       PathFillConvex(col);
    1010    }
    1011    else
    1012    {
    1013       PrimReserve(6, 4);
    1014       PrimRect(a, b, col);
    1015    }
    1016 }
    1017 
    1018 void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
    1019 {
    1020    if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
    1021       return;
    1022 
    1023    const ImVec2 uv = _Data->TexUvWhitePixel;
    1024    PrimReserve(6, 4);
    1025    PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2));
    1026    PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx + 3));
    1027    PrimWriteVtx(a, uv, col_upr_left);
    1028    PrimWriteVtx(ImVec2(c.x, a.y), uv, col_upr_right);
    1029    PrimWriteVtx(c, uv, col_bot_right);
    1030    PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left);
    1031 }
    1032 
    1033 void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness)
    1034 {
    1035    if ((col & IM_COL32_A_MASK) == 0)
    1036       return;
    1037 
    1038    PathLineTo(a);
    1039    PathLineTo(b);
    1040    PathLineTo(c);
    1041    PathLineTo(d);
    1042    PathStroke(col, true, thickness);
    1043 }
    1044 
    1045 void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col)
    1046 {
    1047    if ((col & IM_COL32_A_MASK) == 0)
    1048       return;
    1049 
    1050    PathLineTo(a);
    1051    PathLineTo(b);
    1052    PathLineTo(c);
    1053    PathLineTo(d);
    1054    PathFillConvex(col);
    1055 }
    1056 
    1057 void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness)
    1058 {
    1059    if ((col & IM_COL32_A_MASK) == 0)
    1060       return;
    1061 
    1062    PathLineTo(a);
    1063    PathLineTo(b);
    1064    PathLineTo(c);
    1065    PathStroke(col, true, thickness);
    1066 }
    1067 
    1068 void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col)
    1069 {
    1070    if ((col & IM_COL32_A_MASK) == 0)
    1071       return;
    1072 
    1073    PathLineTo(a);
    1074    PathLineTo(b);
    1075    PathLineTo(c);
    1076    PathFillConvex(col);
    1077 }
    1078 
    1079 void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
    1080 {
    1081    if ((col & IM_COL32_A_MASK) == 0)
    1082       return;
    1083 
    1084    const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
    1085    PathArcTo(centre, radius - 0.5f, 0.0f, a_max, num_segments);
    1086    PathStroke(col, true, thickness);
    1087 }
    1088 
    1089 void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
    1090 {
    1091    if ((col & IM_COL32_A_MASK) == 0)
    1092       return;
    1093 
    1094    const float a_max = IM_PI * 2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
    1095    PathArcTo(centre, radius, 0.0f, a_max, num_segments);
    1096    PathFillConvex(col);
    1097 }
    1098 
    1099 void ImDrawList::AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments)
    1100 {
    1101    if ((col & IM_COL32_A_MASK) == 0)
    1102       return;
    1103 
    1104    PathLineTo(pos0);
    1105    PathBezierCurveTo(cp0, cp1, pos1, num_segments);
    1106    PathStroke(col, false, thickness);
    1107 }
    1108 
    1109 void ImDrawList::AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end, float wrap_width, const ImVec4* cpu_fine_clip_rect)
    1110 {
    1111    if ((col & IM_COL32_A_MASK) == 0)
    1112       return;
    1113 
    1114    if (text_end == NULL)
    1115       text_end = text_begin + strlen(text_begin);
    1116    if (text_begin == text_end)
    1117       return;
    1118 
    1119    // Pull default font/size from the shared ImDrawListSharedData instance
    1120    if (font == NULL)
    1121       font = _Data->Font;
    1122    if (font_size == 0.0f)
    1123       font_size = _Data->FontSize;
    1124 
    1125    IM_ASSERT(font->ContainerAtlas->TexID == _TextureIdStack.back());  // Use high-level ImGui::PushFont() or low-level ImDrawList::PushTextureId() to change font.
    1126 
    1127    ImVec4 clip_rect = _ClipRectStack.back();
    1128    if (cpu_fine_clip_rect)
    1129    {
    1130       clip_rect.x = ImMax(clip_rect.x, cpu_fine_clip_rect->x);
    1131       clip_rect.y = ImMax(clip_rect.y, cpu_fine_clip_rect->y);
    1132       clip_rect.z = ImMin(clip_rect.z, cpu_fine_clip_rect->z);
    1133       clip_rect.w = ImMin(clip_rect.w, cpu_fine_clip_rect->w);
    1134    }
    1135    font->RenderText(this, font_size, pos, col, clip_rect, text_begin, text_end, wrap_width, cpu_fine_clip_rect != NULL);
    1136 }
    1137 
    1138 void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end)
    1139 {
    1140    AddText(NULL, 0.0f, pos, col, text_begin, text_end);
    1141 }
    1142 
    1143 void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col)
    1144 {
    1145    if ((col & IM_COL32_A_MASK) == 0)
    1146       return;
    1147 
    1148    const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
    1149    if (push_texture_id)
    1150       PushTextureID(user_texture_id);
    1151 
    1152    PrimReserve(6, 4);
    1153    PrimRectUV(a, b, uv_a, uv_b, col);
    1154 
    1155    if (push_texture_id)
    1156       PopTextureID();
    1157 }
    1158 
    1159 void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col)
    1160 {
    1161    if ((col & IM_COL32_A_MASK) == 0)
    1162       return;
    1163 
    1164    const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
    1165    if (push_texture_id)
    1166       PushTextureID(user_texture_id);
    1167 
    1168    PrimReserve(6, 4);
    1169    PrimQuadUV(a, b, c, d, uv_a, uv_b, uv_c, uv_d, col);
    1170 
    1171    if (push_texture_id)
    1172       PopTextureID();
    1173 }
    1174 
    1175 void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners)
    1176 {
    1177    if ((col & IM_COL32_A_MASK) == 0)
    1178       return;
    1179 
    1180    if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0)
    1181    {
    1182       AddImage(user_texture_id, a, b, uv_a, uv_b, col);
    1183       return;
    1184    }
    1185 
    1186    const bool push_texture_id = _TextureIdStack.empty() || user_texture_id != _TextureIdStack.back();
    1187    if (push_texture_id)
    1188       PushTextureID(user_texture_id);
    1189 
    1190    int vert_start_idx = VtxBuffer.Size;
    1191    PathRect(a, b, rounding, rounding_corners);
    1192    PathFillConvex(col);
    1193    int vert_end_idx = VtxBuffer.Size;
    1194    ImGui::ShadeVertsLinearUV(VtxBuffer.Data + vert_start_idx, VtxBuffer.Data + vert_end_idx, a, b, uv_a, uv_b, true);
    1195 
    1196    if (push_texture_id)
    1197       PopTextureID();
     1491        }
     1492        if (ch._CmdBuffer.Size > 0)
     1493            last_cmd = &ch._CmdBuffer.back();
     1494        new_cmd_buffer_count += ch._CmdBuffer.Size;
     1495        new_idx_buffer_count += ch._IdxBuffer.Size;
     1496        for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++)
     1497        {
     1498            ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset;
     1499            idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount;
     1500        }
     1501    }
     1502    draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count);
     1503    draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count);
     1504
     1505    // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices)
     1506    ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count;
     1507    ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count;
     1508    for (int i = 1; i < _Count; i++)
     1509    {
     1510        ImDrawChannel& ch = _Channels[i];
     1511        if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
     1512        if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; }
     1513    }
     1514    draw_list->_IdxWritePtr = idx_write;
     1515
     1516    // Ensure there's always a non-callback draw command trailing the command-buffer
     1517    if (draw_list->CmdBuffer.Size == 0 || draw_list->CmdBuffer.back().UserCallback != NULL)
     1518        draw_list->AddDrawCmd();
     1519
     1520    // If current command is used with different settings we need to add a new command
     1521    ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
     1522    if (curr_cmd->ElemCount == 0)
     1523        ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
     1524    else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
     1525        draw_list->AddDrawCmd();
     1526
     1527    _Count = 1;
     1528}
     1529
     1530void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
     1531{
     1532    IM_ASSERT(idx >= 0 && idx < _Count);
     1533    if (_Current == idx)
     1534        return;
     1535
     1536    // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
     1537    memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
     1538    memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));
     1539    _Current = idx;
     1540    memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));
     1541    memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));
     1542    draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;
     1543
     1544    // If current command is used with different settings we need to add a new command
     1545    ImDrawCmd* curr_cmd = &draw_list->CmdBuffer.Data[draw_list->CmdBuffer.Size - 1];
     1546    if (curr_cmd->ElemCount == 0)
     1547        ImDrawCmd_HeaderCopy(curr_cmd, &draw_list->_CmdHeader); // Copy ClipRect, TextureId, VtxOffset
     1548    else if (ImDrawCmd_HeaderCompare(curr_cmd, &draw_list->_CmdHeader) != 0)
     1549        draw_list->AddDrawCmd();
    11981550}
    11991551
    12001552//-----------------------------------------------------------------------------
    1201 // ImDrawData
     1553// [SECTION] ImDrawData
    12021554//-----------------------------------------------------------------------------
    12031555
     
    12051557void ImDrawData::DeIndexAllBuffers()
    12061558{
    1207    ImVector<ImDrawVert> new_vtx_buffer;
    1208    TotalVtxCount = TotalIdxCount = 0;
    1209    for (int i = 0; i < CmdListsCount; i++)
    1210    {
    1211       ImDrawList* cmd_list = CmdLists[i];
    1212       if (cmd_list->IdxBuffer.empty())
    1213          continue;
    1214       new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
    1215       for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
    1216          new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
    1217       cmd_list->VtxBuffer.swap(new_vtx_buffer);
    1218       cmd_list->IdxBuffer.resize(0);
    1219       TotalVtxCount += cmd_list->VtxBuffer.Size;
    1220    }
    1221 }
    1222 
    1223 // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
    1224 void ImDrawData::ScaleClipRects(const ImVec2& scale)
    1225 {
    1226    for (int i = 0; i < CmdListsCount; i++)
    1227    {
    1228       ImDrawList* cmd_list = CmdLists[i];
    1229       for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
    1230       {
    1231          ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
    1232          cmd->ClipRect = ImVec4(cmd->ClipRect.x * scale.x, cmd->ClipRect.y * scale.y, cmd->ClipRect.z * scale.x, cmd->ClipRect.w * scale.y);
    1233       }
    1234    }
     1559    ImVector<ImDrawVert> new_vtx_buffer;
     1560    TotalVtxCount = TotalIdxCount = 0;
     1561    for (int i = 0; i < CmdListsCount; i++)
     1562    {
     1563        ImDrawList* cmd_list = CmdLists[i];
     1564        if (cmd_list->IdxBuffer.empty())
     1565            continue;
     1566        new_vtx_buffer.resize(cmd_list->IdxBuffer.Size);
     1567        for (int j = 0; j < cmd_list->IdxBuffer.Size; j++)
     1568            new_vtx_buffer[j] = cmd_list->VtxBuffer[cmd_list->IdxBuffer[j]];
     1569        cmd_list->VtxBuffer.swap(new_vtx_buffer);
     1570        cmd_list->IdxBuffer.resize(0);
     1571        TotalVtxCount += cmd_list->VtxBuffer.Size;
     1572    }
     1573}
     1574
     1575// Helper to scale the ClipRect field of each ImDrawCmd.
     1576// Use if your final output buffer is at a different scale than draw_data->DisplaySize,
     1577// or if there is a difference between your window resolution and framebuffer resolution.
     1578void ImDrawData::ScaleClipRects(const ImVec2& fb_scale)
     1579{
     1580    for (int i = 0; i < CmdListsCount; i++)
     1581    {
     1582        ImDrawList* cmd_list = CmdLists[i];
     1583        for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
     1584        {
     1585            ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
     1586            cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y);
     1587        }
     1588    }
    12351589}
    12361590
    12371591//-----------------------------------------------------------------------------
    1238 // Shade functions
     1592// [SECTION] Helpers ShadeVertsXXX functions
    12391593//-----------------------------------------------------------------------------
    12401594
    12411595// Generic linear color gradient, write to RGB fields, leave A untouched.
    1242 void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
    1243 {
    1244    ImVec2 gradient_extent = gradient_p1 - gradient_p0;
    1245    float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
    1246    for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
    1247    {
    1248       float d = ImDot(vert->pos - gradient_p0, gradient_extent);
    1249       float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
    1250       int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t);
    1251       int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t);
    1252       int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t);
    1253       vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);
    1254    }
    1255 }
    1256 
    1257 // Scan and shade backward from the end of given vertices. Assume vertices are text only (= vert_start..vert_end going left to right) so we can break as soon as we are out the gradient bounds.
    1258 void ImGui::ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x)
    1259 {
    1260    float gradient_extent_x = gradient_p1_x - gradient_p0_x;
    1261    float gradient_inv_length2 = 1.0f / (gradient_extent_x * gradient_extent_x);
    1262    int full_alpha_count = 0;
    1263    for (ImDrawVert* vert = vert_end - 1; vert >= vert_start; vert--)
    1264    {
    1265       float d = (vert->pos.x - gradient_p0_x) * (gradient_extent_x);
    1266       float alpha_mul = 1.0f - ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
    1267       if (alpha_mul >= 1.0f && ++full_alpha_count > 2)
    1268          return; // Early out
    1269       int a = (int)(((vert->col >> IM_COL32_A_SHIFT) & 0xFF) * alpha_mul);
    1270       vert->col = (vert->col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
    1271    }
     1596void ImGui::ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
     1597{
     1598    ImVec2 gradient_extent = gradient_p1 - gradient_p0;
     1599    float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
     1600    ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
     1601    ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
     1602    const int col0_r = (int)(col0 >> IM_COL32_R_SHIFT) & 0xFF;
     1603    const int col0_g = (int)(col0 >> IM_COL32_G_SHIFT) & 0xFF;
     1604    const int col0_b = (int)(col0 >> IM_COL32_B_SHIFT) & 0xFF;
     1605    const int col_delta_r = ((int)(col1 >> IM_COL32_R_SHIFT) & 0xFF) - col0_r;
     1606    const int col_delta_g = ((int)(col1 >> IM_COL32_G_SHIFT) & 0xFF) - col0_g;
     1607    const int col_delta_b = ((int)(col1 >> IM_COL32_B_SHIFT) & 0xFF) - col0_b;
     1608    for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
     1609    {
     1610        float d = ImDot(vert->pos - gradient_p0, gradient_extent);
     1611        float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
     1612        int r = (int)(col0_r + col_delta_r * t);
     1613        int g = (int)(col0_g + col_delta_g * t);
     1614        int b = (int)(col0_b + col_delta_b * t);
     1615        vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);
     1616    }
    12721617}
    12731618
    12741619// Distribute UV over (a, b) rectangle
    1275 void ImGui::ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp)
    1276 {
    1277    const ImVec2 size = b - a;
    1278    const ImVec2 uv_size = uv_b - uv_a;
    1279    const ImVec2 scale = ImVec2(
    1280       size.x != 0.0f ? (uv_size.x / size.x) : 0.0f,
    1281       size.y != 0.0f ? (uv_size.y / size.y) : 0.0f);
    1282 
    1283    if (clamp)
    1284    {
    1285       const ImVec2 min = ImMin(uv_a, uv_b);
    1286       const ImVec2 max = ImMax(uv_a, uv_b);
    1287 
    1288       for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
    1289          vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max);
    1290    }
    1291    else
    1292    {
    1293       for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
    1294          vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);
    1295    }
     1620void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp)
     1621{
     1622    const ImVec2 size = b - a;
     1623    const ImVec2 uv_size = uv_b - uv_a;
     1624    const ImVec2 scale = ImVec2(
     1625        size.x != 0.0f ? (uv_size.x / size.x) : 0.0f,
     1626        size.y != 0.0f ? (uv_size.y / size.y) : 0.0f);
     1627
     1628    ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
     1629    ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
     1630    if (clamp)
     1631    {
     1632        const ImVec2 min = ImMin(uv_a, uv_b);
     1633        const ImVec2 max = ImMax(uv_a, uv_b);
     1634        for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
     1635            vertex->uv = ImClamp(uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale), min, max);
     1636    }
     1637    else
     1638    {
     1639        for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
     1640            vertex->uv = uv_a + ImMul(ImVec2(vertex->pos.x, vertex->pos.y) - a, scale);
     1641    }
    12961642}
    12971643
    12981644//-----------------------------------------------------------------------------
    1299 // ImFontConfig
     1645// [SECTION] ImFontConfig
    13001646//-----------------------------------------------------------------------------
    13011647
    13021648ImFontConfig::ImFontConfig()
    13031649{
    1304    FontData = NULL;
    1305    FontDataSize = 0;
    1306    FontDataOwnedByAtlas = true;
    1307    FontNo = 0;
    1308    SizePixels = 0.0f;
    1309    OversampleH = 3;
    1310    OversampleV = 1;
    1311    PixelSnapH = false;
    1312    GlyphExtraSpacing = ImVec2(0.0f, 0.0f);
    1313    GlyphOffset = ImVec2(0.0f, 0.0f);
    1314    GlyphRanges = NULL;
    1315    MergeMode = false;
    1316    RasterizerFlags = 0x00;
    1317    RasterizerMultiply = 1.0f;
    1318    memset(Name, 0, sizeof(Name));
    1319    DstFont = NULL;
     1650    FontData = NULL;
     1651    FontDataSize = 0;
     1652    FontDataOwnedByAtlas = true;
     1653    FontNo = 0;
     1654    SizePixels = 0.0f;
     1655    OversampleH = 3; // FIXME: 2 may be a better default?
     1656    OversampleV = 1;
     1657    PixelSnapH = false;
     1658    GlyphExtraSpacing = ImVec2(0.0f, 0.0f);
     1659    GlyphOffset = ImVec2(0.0f, 0.0f);
     1660    GlyphRanges = NULL;
     1661    GlyphMinAdvanceX = 0.0f;
     1662    GlyphMaxAdvanceX = FLT_MAX;
     1663    MergeMode = false;
     1664    RasterizerFlags = 0x00;
     1665    RasterizerMultiply = 1.0f;
     1666    EllipsisChar = (ImWchar)-1;
     1667    memset(Name, 0, sizeof(Name));
     1668    DstFont = NULL;
    13201669}
    13211670
    13221671//-----------------------------------------------------------------------------
    1323 // ImFontAtlas
     1672// [SECTION] ImFontAtlas
    13241673//-----------------------------------------------------------------------------
    13251674
    13261675// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
    1327 // The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes.
    1328 const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 90;
     1676// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
     1677const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 108; // Actual texture will be 2 times that + 1 spacing.
    13291678const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
    1330 const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000;
    1331 static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
    1332 {
    1333    "..-         -XXXXXXX-    X    -           X           -XXXXXXX          -          XXXXXXX"
    1334    "..-         -X.....X-   X.X   -          X.X          -X.....X          -          X.....X"
    1335    "---         -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X"
    1336    "X           -  X.X  - X.....X -        X.....X        -X...X            -            X...X"
    1337    "XX          -  X.X  -X.......X-       X.......X       -X..X.X           -           X.X..X"
    1338    "X.X         -  X.X  -XXXX.XXXX-       XXXX.XXXX       -X.X X.X          -          X.X X.X"
    1339    "X..X        -  X.X  -   X.X   -          X.X          -XX   X.X         -         X.X   XX"
    1340    "X...X       -  X.X  -   X.X   -    XX    X.X    XX    -      X.X        -        X.X      "
    1341    "X....X      -  X.X  -   X.X   -   X.X    X.X    X.X   -       X.X       -       X.X       "
    1342    "X.....X     -  X.X  -   X.X   -  X..X    X.X    X..X  -        X.X      -      X.X        "
    1343    "X......X    -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -         X.X   XX-XX   X.X         "
    1344    "X.......X   -  X.X  -   X.X   -X.....................X-          X.X X.X-X.X X.X          "
    1345    "X........X  -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -           X.X..X-X..X.X           "
    1346    "X.........X -XXX.XXX-   X.X   -  X..X    X.X    X..X  -            X...X-X...X            "
    1347    "X..........X-X.....X-   X.X   -   X.X    X.X    X.X   -           X....X-X....X           "
    1348    "X......XXXXX-XXXXXXX-   X.X   -    XX    X.X    XX    -          X.....X-X.....X          "
    1349    "X...X..X    ---------   X.X   -          X.X          -          XXXXXXX-XXXXXXX          "
    1350    "X..X X..X   -       -XXXX.XXXX-       XXXX.XXXX       ------------------------------------"
    1351    "X.X  X..X   -       -X.......X-       X.......X       -    XX           XX    -           "
    1352    "XX    X..X  -       - X.....X -        X.....X        -   X.X           X.X   -           "
    1353    "      X..X          -  X...X  -         X...X         -  X..X           X..X  -           "
    1354    "       XX           -   X.X   -          X.X          - X...XXXXXXXXXXXXX...X -           "
    1355    "------------        -    X    -           X           -X.....................X-           "
    1356    "                    ----------------------------------- X...XXXXXXXXXXXXX...X -           "
    1357    "                                                      -  X..X           X..X  -           "
    1358    "                                                      -   X.X           X.X   -           "
    1359    "                                                      -    XX           XX    -           "
     1679static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
     1680{
     1681    "..-         -XXXXXXX-    X    -           X           -XXXXXXX          -          XXXXXXX-     XX          "
     1682    "..-         -X.....X-   X.X   -          X.X          -X.....X          -          X.....X-    X..X         "
     1683    "---         -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X-    X..X         "
     1684    "X           -  X.X  - X.....X -        X.....X        -X...X            -            X...X-    X..X         "
     1685    "XX          -  X.X  -X.......X-       X.......X       -X..X.X           -           X.X..X-    X..X         "
     1686    "X.X         -  X.X  -XXXX.XXXX-       XXXX.XXXX       -X.X X.X          -          X.X X.X-    X..XXX       "
     1687    "X..X        -  X.X  -   X.X   -          X.X          -XX   X.X         -         X.X   XX-    X..X..XXX    "
     1688    "X...X       -  X.X  -   X.X   -    XX    X.X    XX    -      X.X        -        X.X      -    X..X..X..XX  "
     1689    "X....X      -  X.X  -   X.X   -   X.X    X.X    X.X   -       X.X       -       X.X       -    X..X..X..X.X "
     1690    "X.....X     -  X.X  -   X.X   -  X..X    X.X    X..X  -        X.X      -      X.X        -XXX X..X..X..X..X"
     1691    "X......X    -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -         X.X   XX-XX   X.X         -X..XX........X..X"
     1692    "X.......X   -  X.X  -   X.X   -X.....................X-          X.X X.X-X.X X.X          -X...X...........X"
     1693    "X........X  -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -           X.X..X-X..X.X           - X..............X"
     1694    "X.........X -XXX.XXX-   X.X   -  X..X    X.X    X..X  -            X...X-X...X            -  X.............X"
     1695    "X..........X-X.....X-   X.X   -   X.X    X.X    X.X   -           X....X-X....X           -  X.............X"
     1696    "X......XXXXX-XXXXXXX-   X.X   -    XX    X.X    XX    -          X.....X-X.....X          -   X............X"
     1697    "X...X..X    ---------   X.X   -          X.X          -          XXXXXXX-XXXXXXX          -   X...........X "
     1698    "X..X X..X   -       -XXXX.XXXX-       XXXX.XXXX       -------------------------------------    X..........X "
     1699    "X.X  X..X   -       -X.......X-       X.......X       -    XX           XX    -           -    X..........X "
     1700    "XX    X..X  -       - X.....X -        X.....X        -   X.X           X.X   -           -     X........X  "
     1701    "      X..X          -  X...X  -         X...X         -  X..X           X..X  -           -     X........X  "
     1702    "       XX           -   X.X   -          X.X          - X...XXXXXXXXXXXXX...X -           -     XXXXXXXXXX  "
     1703    "------------        -    X    -           X           -X.....................X-           ------------------"
     1704    "                    ----------------------------------- X...XXXXXXXXXXXXX...X -                             "
     1705    "                                                      -  X..X           X..X  -                             "
     1706    "                                                      -   X.X           X.X   -                             "
     1707    "                                                      -    XX           XX    -                             "
    13601708};
    13611709
    13621710static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] =
    13631711{
    1364    // Pos ........ Size ......... Offset ......
    1365    { ImVec2(0,3),  ImVec2(12,19), ImVec2(0, 0) }, // ImGuiMouseCursor_Arrow
    1366 { ImVec2(13,0), ImVec2(7,16),  ImVec2(4, 8) }, // ImGuiMouseCursor_TextInput
    1367 { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll
    1368 { ImVec2(21,0), ImVec2(9,23), ImVec2(5,11) }, // ImGuiMouseCursor_ResizeNS
    1369 { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 5) }, // ImGuiMouseCursor_ResizeEW
    1370 { ImVec2(73,0), ImVec2(17,17), ImVec2(9, 9) }, // ImGuiMouseCursor_ResizeNESW
    1371 { ImVec2(55,0), ImVec2(17,17), ImVec2(9, 9) }, // ImGuiMouseCursor_ResizeNWSE
     1712    // Pos ........ Size ......... Offset ......
     1713    { ImVec2( 0,3), ImVec2(12,19), ImVec2( 0, 0) }, // ImGuiMouseCursor_Arrow
     1714    { ImVec2(13,0), ImVec2( 7,16), ImVec2( 1, 8) }, // ImGuiMouseCursor_TextInput
     1715    { ImVec2(31,0), ImVec2(23,23), ImVec2(11,11) }, // ImGuiMouseCursor_ResizeAll
     1716    { ImVec2(21,0), ImVec2( 9,23), ImVec2( 4,11) }, // ImGuiMouseCursor_ResizeNS
     1717    { ImVec2(55,18),ImVec2(23, 9), ImVec2(11, 4) }, // ImGuiMouseCursor_ResizeEW
     1718    { ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
     1719    { ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
     1720    { ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
    13721721};
    13731722
    13741723ImFontAtlas::ImFontAtlas()
    13751724{
    1376    Flags = 0x00;
    1377    TexID = NULL;
    1378    TexDesiredWidth = 0;
    1379    TexGlyphPadding = 1;
    1380 
    1381    TexPixelsAlpha8 = NULL;
    1382    TexPixelsRGBA32 = NULL;
    1383    TexWidth = TexHeight = 0;
    1384    TexUvScale = ImVec2(0.0f, 0.0f);
    1385    TexUvWhitePixel = ImVec2(0.0f, 0.0f);
    1386    for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
    1387       CustomRectIds[n] = -1;
     1725    Locked = false;
     1726    Flags = ImFontAtlasFlags_None;
     1727    TexID = (ImTextureID)NULL;
     1728    TexDesiredWidth = 0;
     1729    TexGlyphPadding = 1;
     1730
     1731    TexPixelsAlpha8 = NULL;
     1732    TexPixelsRGBA32 = NULL;
     1733    TexWidth = TexHeight = 0;
     1734    TexUvScale = ImVec2(0.0f, 0.0f);
     1735    TexUvWhitePixel = ImVec2(0.0f, 0.0f);
     1736    PackIdMouseCursors = PackIdLines = -1;
    13881737}
    13891738
    13901739ImFontAtlas::~ImFontAtlas()
    13911740{
    1392    Clear();
     1741    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
     1742    Clear();
    13931743}
    13941744
    13951745void    ImFontAtlas::ClearInputData()
    13961746{
    1397    for (int i = 0; i < ConfigData.Size; i++)
    1398       if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
    1399       {
    1400          ImGui::MemFree(ConfigData[i].FontData);
    1401          ConfigData[i].FontData = NULL;
    1402       }
    1403 
    1404    // When clearing this we lose access to the font name and other information used to build the font.
    1405    for (int i = 0; i < Fonts.Size; i++)
    1406       if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
    1407       {
    1408          Fonts[i]->ConfigData = NULL;
    1409          Fonts[i]->ConfigDataCount = 0;
    1410       }
    1411    ConfigData.clear();
    1412    CustomRects.clear();
    1413    for (int n = 0; n < IM_ARRAYSIZE(CustomRectIds); n++)
    1414       CustomRectIds[n] = -1;
     1747    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
     1748    for (int i = 0; i < ConfigData.Size; i++)
     1749        if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas)
     1750        {
     1751            IM_FREE(ConfigData[i].FontData);
     1752            ConfigData[i].FontData = NULL;
     1753        }
     1754
     1755    // When clearing this we lose access to the font name and other information used to build the font.
     1756    for (int i = 0; i < Fonts.Size; i++)
     1757        if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size)
     1758        {
     1759            Fonts[i]->ConfigData = NULL;
     1760            Fonts[i]->ConfigDataCount = 0;
     1761        }
     1762    ConfigData.clear();
     1763    CustomRects.clear();
     1764    PackIdMouseCursors = PackIdLines = -1;
    14151765}
    14161766
    14171767void    ImFontAtlas::ClearTexData()
    14181768{
    1419    if (TexPixelsAlpha8)
    1420       ImGui::MemFree(TexPixelsAlpha8);
    1421    if (TexPixelsRGBA32)
    1422       ImGui::MemFree(TexPixelsRGBA32);
    1423    TexPixelsAlpha8 = NULL;
    1424    TexPixelsRGBA32 = NULL;
     1769    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
     1770    if (TexPixelsAlpha8)
     1771        IM_FREE(TexPixelsAlpha8);
     1772    if (TexPixelsRGBA32)
     1773        IM_FREE(TexPixelsRGBA32);
     1774    TexPixelsAlpha8 = NULL;
     1775    TexPixelsRGBA32 = NULL;
    14251776}
    14261777
    14271778void    ImFontAtlas::ClearFonts()
    14281779{
    1429    for (int i = 0; i < Fonts.Size; i++)
    1430       IM_DELETE(Fonts[i]);
    1431    Fonts.clear();
     1780    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
     1781    for (int i = 0; i < Fonts.Size; i++)
     1782        IM_DELETE(Fonts[i]);
     1783    Fonts.clear();
    14321784}
    14331785
    14341786void    ImFontAtlas::Clear()
    14351787{
    1436    ClearInputData();
    1437    ClearTexData();
    1438    ClearFonts();
     1788    ClearInputData();
     1789    ClearTexData();
     1790    ClearFonts();
    14391791}
    14401792
    14411793void    ImFontAtlas::GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
    14421794{
    1443    // Build atlas on demand
    1444    if (TexPixelsAlpha8 == NULL)
    1445    {
    1446       if (ConfigData.empty())
    1447          AddFontDefault();
    1448       Build();
    1449    }
    1450 
    1451    *out_pixels = TexPixelsAlpha8;
    1452    if (out_width) *out_width = TexWidth;
    1453    if (out_height) *out_height = TexHeight;
    1454    if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
     1795    // Build atlas on demand
     1796    if (TexPixelsAlpha8 == NULL)
     1797    {
     1798        if (ConfigData.empty())
     1799            AddFontDefault();
     1800        Build();
     1801    }
     1802
     1803    *out_pixels = TexPixelsAlpha8;
     1804    if (out_width) *out_width = TexWidth;
     1805    if (out_height) *out_height = TexHeight;
     1806    if (out_bytes_per_pixel) *out_bytes_per_pixel = 1;
    14551807}
    14561808
    14571809void    ImFontAtlas::GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel)
    14581810{
    1459    // Convert to RGBA32 format on demand
    1460    // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
    1461    if (!TexPixelsRGBA32)
    1462    {
    1463       unsigned char* pixels = NULL;
    1464       GetTexDataAsAlpha8(&pixels, NULL, NULL);
    1465       if (pixels)
    1466       {
    1467          TexPixelsRGBA32 = (unsigned int*)ImGui::MemAlloc((size_t)(TexWidth * TexHeight * 4));
    1468          const unsigned char* src = pixels;
    1469          unsigned int* dst = TexPixelsRGBA32;
    1470          for (int n = TexWidth * TexHeight; n > 0; n--)
    1471             *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
    1472       }
    1473    }
    1474 
    1475    *out_pixels = (unsigned char*)TexPixelsRGBA32;
    1476    if (out_width) *out_width = TexWidth;
    1477    if (out_height) *out_height = TexHeight;
    1478    if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
     1811    // Convert to RGBA32 format on demand
     1812    // Although it is likely to be the most commonly used format, our font rendering is 1 channel / 8 bpp
     1813    if (!TexPixelsRGBA32)
     1814    {
     1815        unsigned char* pixels = NULL;
     1816        GetTexDataAsAlpha8(&pixels, NULL, NULL);
     1817        if (pixels)
     1818        {
     1819            TexPixelsRGBA32 = (unsigned int*)IM_ALLOC((size_t)TexWidth * (size_t)TexHeight * 4);
     1820            const unsigned char* src = pixels;
     1821            unsigned int* dst = TexPixelsRGBA32;
     1822            for (int n = TexWidth * TexHeight; n > 0; n--)
     1823                *dst++ = IM_COL32(255, 255, 255, (unsigned int)(*src++));
     1824        }
     1825    }
     1826
     1827    *out_pixels = (unsigned char*)TexPixelsRGBA32;
     1828    if (out_width) *out_width = TexWidth;
     1829    if (out_height) *out_height = TexHeight;
     1830    if (out_bytes_per_pixel) *out_bytes_per_pixel = 4;
    14791831}
    14801832
    14811833ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
    14821834{
    1483    IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
    1484    IM_ASSERT(font_cfg->SizePixels > 0.0f);
    1485 
    1486    // Create new font
    1487    if (!font_cfg->MergeMode)
    1488       Fonts.push_back(IM_NEW(ImFont));
    1489    else
    1490       IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
    1491 
    1492    ConfigData.push_back(*font_cfg);
    1493    ImFontConfig& new_font_cfg = ConfigData.back();
    1494    if (!new_font_cfg.DstFont)
    1495       new_font_cfg.DstFont = Fonts.back();
    1496    if (!new_font_cfg.FontDataOwnedByAtlas)
    1497    {
    1498       new_font_cfg.FontData = ImGui::MemAlloc(new_font_cfg.FontDataSize);
    1499       new_font_cfg.FontDataOwnedByAtlas = true;
    1500       memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
    1501    }
    1502 
    1503    // Invalidate texture
    1504    ClearTexData();
    1505    return new_font_cfg.DstFont;
     1835    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
     1836    IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
     1837    IM_ASSERT(font_cfg->SizePixels > 0.0f);
     1838
     1839    // Create new font
     1840    if (!font_cfg->MergeMode)
     1841        Fonts.push_back(IM_NEW(ImFont));
     1842    else
     1843        IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
     1844
     1845    ConfigData.push_back(*font_cfg);
     1846    ImFontConfig& new_font_cfg = ConfigData.back();
     1847    if (new_font_cfg.DstFont == NULL)
     1848        new_font_cfg.DstFont = Fonts.back();
     1849    if (!new_font_cfg.FontDataOwnedByAtlas)
     1850    {
     1851        new_font_cfg.FontData = IM_ALLOC(new_font_cfg.FontDataSize);
     1852        new_font_cfg.FontDataOwnedByAtlas = true;
     1853        memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
     1854    }
     1855
     1856    if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1)
     1857        new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;
     1858
     1859    // Invalidate texture
     1860    ClearTexData();
     1861    return new_font_cfg.DstFont;
    15061862}
    15071863
    15081864// Default font TTF is compressed with stb_compress then base85 encoded (see misc/fonts/binary_to_compressed_c.cpp for encoder)
    1509 static unsigned int stb_decompress_length(const unsigned char *input);
    1510 static unsigned int stb_decompress(unsigned char *output, const unsigned char *input, unsigned int length);
     1865static unsigned int stb_decompress_length(const unsigned char* input);
     1866static unsigned int stb_decompress(unsigned char* output, const unsigned char* input, unsigned int length);
    15111867static const char*  GetDefaultCompressedFontDataTTFBase85();
    1512 static unsigned int Decode85Byte(char c) { return c >= '\\' ? c - 36 : c - 35; }
     1868static unsigned int Decode85Byte(char c)                                    { return c >= '\\' ? c-36 : c-35; }
    15131869static void         Decode85(const unsigned char* src, unsigned char* dst)
    15141870{
    1515    while (*src)
    1516    {
    1517       unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));
    1518       dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF);   // We can't assume little-endianness.
    1519       src += 5;
    1520       dst += 4;
    1521    }
     1871    while (*src)
     1872    {
     1873        unsigned int tmp = Decode85Byte(src[0]) + 85 * (Decode85Byte(src[1]) + 85 * (Decode85Byte(src[2]) + 85 * (Decode85Byte(src[3]) + 85 * Decode85Byte(src[4]))));
     1874        dst[0] = ((tmp >> 0) & 0xFF); dst[1] = ((tmp >> 8) & 0xFF); dst[2] = ((tmp >> 16) & 0xFF); dst[3] = ((tmp >> 24) & 0xFF);   // We can't assume little-endianness.
     1875        src += 5;
     1876        dst += 4;
     1877    }
    15221878}
    15231879
     
    15251881ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
    15261882{
    1527    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
    1528    if (!font_cfg_template)
    1529    {
    1530       font_cfg.OversampleH = font_cfg.OversampleV = 1;
    1531       font_cfg.PixelSnapH = true;
    1532    }
    1533    if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px");
    1534    if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f;
    1535 
    1536    const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
    1537    ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, GetGlyphRangesDefault());
    1538    font->DisplayOffset.y = 1.0f;
    1539    return font;
     1883    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
     1884    if (!font_cfg_template)
     1885    {
     1886        font_cfg.OversampleH = font_cfg.OversampleV = 1;
     1887        font_cfg.PixelSnapH = true;
     1888    }
     1889    if (font_cfg.SizePixels <= 0.0f)
     1890        font_cfg.SizePixels = 13.0f * 1.0f;
     1891    if (font_cfg.Name[0] == '\0')
     1892        ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels);
     1893    font_cfg.EllipsisChar = (ImWchar)0x0085;
     1894    font_cfg.GlyphOffset.y = 1.0f * IM_FLOOR(font_cfg.SizePixels / 13.0f);  // Add +1 offset per 13 units
     1895
     1896    const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
     1897    const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
     1898    ImFont* font = AddFontFromMemoryCompressedBase85TTF(ttf_compressed_base85, font_cfg.SizePixels, &font_cfg, glyph_ranges);
     1899    return font;
    15401900}
    15411901
    15421902ImFont* ImFontAtlas::AddFontFromFileTTF(const char* filename, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
    15431903{
    1544    int data_size = 0;
    1545    void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
    1546    if (!data)
    1547    {
    1548       IM_ASSERT(0); // Could not load file.
    1549       return NULL;
    1550    }
    1551    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
    1552    if (font_cfg.Name[0] == '\0')
    1553    {
    1554       // Store a short copy of filename into into the font name for convenience
    1555       const char* p;
    1556       for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
    1557       ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
    1558    }
    1559    return AddFontFromMemoryTTF(data, data_size, size_pixels, &font_cfg, glyph_ranges);
     1904    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
     1905    size_t data_size = 0;
     1906    void* data = ImFileLoadToMemory(filename, "rb", &data_size, 0);
     1907    if (!data)
     1908    {
     1909        IM_ASSERT_USER_ERROR(0, "Could not load font file!");
     1910        return NULL;
     1911    }
     1912    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
     1913    if (font_cfg.Name[0] == '\0')
     1914    {
     1915        // Store a short copy of filename into into the font name for convenience
     1916        const char* p;
     1917        for (p = filename + strlen(filename); p > filename && p[-1] != '/' && p[-1] != '\\'; p--) {}
     1918        ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "%s, %.0fpx", p, size_pixels);
     1919    }
     1920    return AddFontFromMemoryTTF(data, (int)data_size, size_pixels, &font_cfg, glyph_ranges);
    15601921}
    15611922
     
    15631924ImFont* ImFontAtlas::AddFontFromMemoryTTF(void* ttf_data, int ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
    15641925{
    1565    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
    1566    IM_ASSERT(font_cfg.FontData == NULL);
    1567    font_cfg.FontData = ttf_data;
    1568    font_cfg.FontDataSize = ttf_size;
    1569    font_cfg.SizePixels = size_pixels;
    1570    if (glyph_ranges)
    1571       font_cfg.GlyphRanges = glyph_ranges;
    1572    return AddFont(&font_cfg);
     1926    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
     1927    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
     1928    IM_ASSERT(font_cfg.FontData == NULL);
     1929    font_cfg.FontData = ttf_data;
     1930    font_cfg.FontDataSize = ttf_size;
     1931    font_cfg.SizePixels = size_pixels;
     1932    if (glyph_ranges)
     1933        font_cfg.GlyphRanges = glyph_ranges;
     1934    return AddFont(&font_cfg);
    15731935}
    15741936
    15751937ImFont* ImFontAtlas::AddFontFromMemoryCompressedTTF(const void* compressed_ttf_data, int compressed_ttf_size, float size_pixels, const ImFontConfig* font_cfg_template, const ImWchar* glyph_ranges)
    15761938{
    1577    const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
    1578    unsigned char* buf_decompressed_data = (unsigned char *)ImGui::MemAlloc(buf_decompressed_size);
    1579    stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
    1580 
    1581    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
    1582    IM_ASSERT(font_cfg.FontData == NULL);
    1583    font_cfg.FontDataOwnedByAtlas = true;
    1584    return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
     1939    const unsigned int buf_decompressed_size = stb_decompress_length((const unsigned char*)compressed_ttf_data);
     1940    unsigned char* buf_decompressed_data = (unsigned char*)IM_ALLOC(buf_decompressed_size);
     1941    stb_decompress(buf_decompressed_data, (const unsigned char*)compressed_ttf_data, (unsigned int)compressed_ttf_size);
     1942
     1943    ImFontConfig font_cfg = font_cfg_template ? *font_cfg_template : ImFontConfig();
     1944    IM_ASSERT(font_cfg.FontData == NULL);
     1945    font_cfg.FontDataOwnedByAtlas = true;
     1946    return AddFontFromMemoryTTF(buf_decompressed_data, (int)buf_decompressed_size, size_pixels, &font_cfg, glyph_ranges);
    15851947}
    15861948
    15871949ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed_ttf_data_base85, float size_pixels, const ImFontConfig* font_cfg, const ImWchar* glyph_ranges)
    15881950{
    1589    int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
    1590    void* compressed_ttf = ImGui::MemAlloc((size_t)compressed_ttf_size);
    1591    Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
    1592    ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
    1593    ImGui::MemFree(compressed_ttf);
    1594    return font;
    1595 }
    1596 
    1597 int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height)
    1598 {
    1599    IM_ASSERT(id >= 0x10000);
    1600    IM_ASSERT(width > 0 && width <= 0xFFFF);
    1601    IM_ASSERT(height > 0 && height <= 0xFFFF);
    1602    CustomRect r;
    1603    r.ID = id;
    1604    r.Width = (unsigned short)width;
    1605    r.Height = (unsigned short)height;
    1606    CustomRects.push_back(r);
    1607    return CustomRects.Size - 1; // Return index
     1951    int compressed_ttf_size = (((int)strlen(compressed_ttf_data_base85) + 4) / 5) * 4;
     1952    void* compressed_ttf = IM_ALLOC((size_t)compressed_ttf_size);
     1953    Decode85((const unsigned char*)compressed_ttf_data_base85, (unsigned char*)compressed_ttf);
     1954    ImFont* font = AddFontFromMemoryCompressedTTF(compressed_ttf, compressed_ttf_size, size_pixels, font_cfg, glyph_ranges);
     1955    IM_FREE(compressed_ttf);
     1956    return font;
     1957}
     1958
     1959int ImFontAtlas::AddCustomRectRegular(int width, int height)
     1960{
     1961    IM_ASSERT(width > 0 && width <= 0xFFFF);
     1962    IM_ASSERT(height > 0 && height <= 0xFFFF);
     1963    ImFontAtlasCustomRect r;
     1964    r.Width = (unsigned short)width;
     1965    r.Height = (unsigned short)height;
     1966    CustomRects.push_back(r);
     1967    return CustomRects.Size - 1; // Return index
    16081968}
    16091969
    16101970int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset)
    16111971{
    1612    IM_ASSERT(font != NULL);
    1613    IM_ASSERT(width > 0 && width <= 0xFFFF);
    1614    IM_ASSERT(height > 0 && height <= 0xFFFF);
    1615    CustomRect r;
    1616    r.ID = id;
    1617    r.Width = (unsigned short)width;
    1618    r.Height = (unsigned short)height;
    1619    r.GlyphAdvanceX = advance_x;
    1620    r.GlyphOffset = offset;
    1621    r.Font = font;
    1622    CustomRects.push_back(r);
    1623    return CustomRects.Size - 1; // Return index
    1624 }
    1625 
    1626 void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max)
    1627 {
    1628    IM_ASSERT(TexWidth > 0 && TexHeight > 0);   // Font atlas needs to be built before we can calculate UV coordinates
    1629    IM_ASSERT(rect->IsPacked());                // Make sure the rectangle has been packed
    1630    *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y);
    1631    *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y);
     1972#ifdef IMGUI_USE_WCHAR32
     1973    IM_ASSERT(id <= IM_UNICODE_CODEPOINT_MAX);
     1974#endif
     1975    IM_ASSERT(font != NULL);
     1976    IM_ASSERT(width > 0 && width <= 0xFFFF);
     1977    IM_ASSERT(height > 0 && height <= 0xFFFF);
     1978    ImFontAtlasCustomRect r;
     1979    r.Width = (unsigned short)width;
     1980    r.Height = (unsigned short)height;
     1981    r.GlyphID = id;
     1982    r.GlyphAdvanceX = advance_x;
     1983    r.GlyphOffset = offset;
     1984    r.Font = font;
     1985    CustomRects.push_back(r);
     1986    return CustomRects.Size - 1; // Return index
     1987}
     1988
     1989void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max) const
     1990{
     1991    IM_ASSERT(TexWidth > 0 && TexHeight > 0);   // Font atlas needs to be built before we can calculate UV coordinates
     1992    IM_ASSERT(rect->IsPacked());                // Make sure the rectangle has been packed
     1993    *out_uv_min = ImVec2((float)rect->X * TexUvScale.x, (float)rect->Y * TexUvScale.y);
     1994    *out_uv_max = ImVec2((float)(rect->X + rect->Width) * TexUvScale.x, (float)(rect->Y + rect->Height) * TexUvScale.y);
    16321995}
    16331996
    16341997bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2])
    16351998{
    1636    if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)
    1637       return false;
    1638    if (Flags & ImFontAtlasFlags_NoMouseCursors)
    1639       return false;
    1640 
    1641    IM_ASSERT(CustomRectIds[0] != -1);
    1642    ImFontAtlas::CustomRect& r = CustomRects[CustomRectIds[0]];
    1643    IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
    1644    ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r.X, (float)r.Y);
    1645    ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
    1646    *out_size = size;
    1647    *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
    1648    out_uv_border[0] = (pos)* TexUvScale;
    1649    out_uv_border[1] = (pos + size) * TexUvScale;
    1650    pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1;
    1651    out_uv_fill[0] = (pos)* TexUvScale;
    1652    out_uv_fill[1] = (pos + size) * TexUvScale;
    1653    return true;
     1999    if (cursor_type <= ImGuiMouseCursor_None || cursor_type >= ImGuiMouseCursor_COUNT)
     2000        return false;
     2001    if (Flags & ImFontAtlasFlags_NoMouseCursors)
     2002        return false;
     2003
     2004    IM_ASSERT(PackIdMouseCursors != -1);
     2005    ImFontAtlasCustomRect* r = GetCustomRectByIndex(PackIdMouseCursors);
     2006    ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r->X, (float)r->Y);
     2007    ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
     2008    *out_size = size;
     2009    *out_offset = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][2];
     2010    out_uv_border[0] = (pos) * TexUvScale;
     2011    out_uv_border[1] = (pos + size) * TexUvScale;
     2012    pos.x += FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
     2013    out_uv_fill[0] = (pos) * TexUvScale;
     2014    out_uv_fill[1] = (pos + size) * TexUvScale;
     2015    return true;
    16542016}
    16552017
    16562018bool    ImFontAtlas::Build()
    16572019{
    1658    return ImFontAtlasBuildWithStbTruetype(this);
     2020    IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
     2021    return ImFontAtlasBuildWithStbTruetype(this);
    16592022}
    16602023
    16612024void    ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_brighten_factor)
    16622025{
    1663    for (unsigned int i = 0; i < 256; i++)
    1664    {
    1665       unsigned int value = (unsigned int)(i * in_brighten_factor);
    1666       out_table[i] = value > 255 ? 255 : (value & 0xFF);
    1667    }
     2026    for (unsigned int i = 0; i < 256; i++)
     2027    {
     2028        unsigned int value = (unsigned int)(i * in_brighten_factor);
     2029        out_table[i] = value > 255 ? 255 : (value & 0xFF);
     2030    }
    16682031}
    16692032
    16702033void    ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride)
    16712034{
    1672    unsigned char* data = pixels + x + y * stride;
    1673    for (int j = h; j > 0; j--, data += stride)
    1674       for (int i = 0; i < w; i++)
    1675          data[i] = table[data[i]];
     2035    unsigned char* data = pixels + x + y * stride;
     2036    for (int j = h; j > 0; j--, data += stride)
     2037        for (int i = 0; i < w; i++)
     2038            data[i] = table[data[i]];
     2039}
     2040
     2041// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
     2042// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
     2043struct ImFontBuildSrcData
     2044{
     2045    stbtt_fontinfo      FontInfo;
     2046    stbtt_pack_range    PackRange;          // Hold the list of codepoints to pack (essentially points to Codepoints.Data)
     2047    stbrp_rect*         Rects;              // Rectangle to pack. We first fill in their size and the packer will give us their position.
     2048    stbtt_packedchar*   PackedChars;        // Output glyphs
     2049    const ImWchar*      SrcRanges;          // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
     2050    int                 DstIndex;           // Index into atlas->Fonts[] and dst_tmp_array[]
     2051    int                 GlyphsHighest;      // Highest requested codepoint
     2052    int                 GlyphsCount;        // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
     2053    ImBitVector         GlyphsSet;          // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
     2054    ImVector<int>       GlyphsList;         // Glyph codepoints list (flattened version of GlyphsMap)
     2055};
     2056
     2057// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
     2058struct ImFontBuildDstData
     2059{
     2060    int                 SrcCount;           // Number of source fonts targeting this destination font.
     2061    int                 GlyphsHighest;
     2062    int                 GlyphsCount;
     2063    ImBitVector         GlyphsSet;          // This is used to resolve collision when multiple sources are merged into a same destination font.
     2064};
     2065
     2066static void UnpackBitVectorToFlatIndexList(const ImBitVector* in, ImVector<int>* out)
     2067{
     2068    IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int));
     2069    const ImU32* it_begin = in->Storage.begin();
     2070    const ImU32* it_end = in->Storage.end();
     2071    for (const ImU32* it = it_begin; it < it_end; it++)
     2072        if (ImU32 entries_32 = *it)
     2073            for (ImU32 bit_n = 0; bit_n < 32; bit_n++)
     2074                if (entries_32 & ((ImU32)1 << bit_n))
     2075                    out->push_back((int)(((it - it_begin) << 5) + bit_n));
    16762076}
    16772077
    16782078bool    ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
    16792079{
    1680    IM_ASSERT(atlas->ConfigData.Size > 0);
    1681 
    1682    ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
    1683 
    1684    atlas->TexID = NULL;
    1685    atlas->TexWidth = atlas->TexHeight = 0;
    1686    atlas->TexUvScale = ImVec2(0.0f, 0.0f);
    1687    atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
    1688    atlas->ClearTexData();
    1689 
    1690    // Count glyphs/ranges
    1691    int total_glyphs_count = 0;
    1692    int total_ranges_count = 0;
    1693    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
    1694    {
    1695       ImFontConfig& cfg = atlas->ConfigData[input_i];
    1696       if (!cfg.GlyphRanges)
    1697          cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
    1698       for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
    1699          total_glyphs_count += (in_range[1] - in_range[0]) + 1;
    1700    }
    1701 
    1702    // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
    1703    // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
    1704    atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
    1705    atlas->TexHeight = 0;
    1706 
    1707    // Start packing
    1708    const int max_tex_height = 1024 * 32;
    1709    stbtt_pack_context spc = {};
    1710    if (!stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL))
    1711       return false;
    1712    stbtt_PackSetOversampling(&spc, 1, 1);
    1713 
    1714    // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
    1715    ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
    1716 
    1717    // Initialize font information (so we can error without any cleanup)
    1718    struct ImFontTempBuildData
    1719    {
    1720       stbtt_fontinfo      FontInfo;
    1721       stbrp_rect*         Rects;
    1722       int                 RectsCount;
    1723       stbtt_pack_range*   Ranges;
    1724       int                 RangesCount;
    1725    };
    1726    ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData));
    1727    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
    1728    {
    1729       ImFontConfig& cfg = atlas->ConfigData[input_i];
    1730       ImFontTempBuildData& tmp = tmp_array[input_i];
    1731       IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
    1732 
    1733       const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
    1734       IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
    1735       if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
    1736       {
    1737          atlas->TexWidth = atlas->TexHeight = 0; // Reset output on failure
    1738          ImGui::MemFree(tmp_array);
    1739          return false;
    1740       }
    1741    }
    1742 
    1743    // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
    1744    int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
    1745    stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
    1746    stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
    1747    stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
    1748    memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
    1749    memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect));              // Unnecessary but let's clear this for the sake of sanity.
    1750    memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
    1751 
    1752    // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
    1753    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
    1754    {
    1755       ImFontConfig& cfg = atlas->ConfigData[input_i];
    1756       ImFontTempBuildData& tmp = tmp_array[input_i];
    1757 
    1758       // Setup ranges
    1759       int font_glyphs_count = 0;
    1760       int font_ranges_count = 0;
    1761       for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
    1762          font_glyphs_count += (in_range[1] - in_range[0]) + 1;
    1763       tmp.Ranges = buf_ranges + buf_ranges_n;
    1764       tmp.RangesCount = font_ranges_count;
    1765       buf_ranges_n += font_ranges_count;
    1766       for (int i = 0; i < font_ranges_count; i++)
    1767       {
    1768          const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
    1769          stbtt_pack_range& range = tmp.Ranges[i];
    1770          range.font_size = cfg.SizePixels;
    1771          range.first_unicode_codepoint_in_range = in_range[0];
    1772          range.num_chars = (in_range[1] - in_range[0]) + 1;
    1773          range.chardata_for_range = buf_packedchars + buf_packedchars_n;
    1774          buf_packedchars_n += range.num_chars;
    1775       }
    1776 
    1777       // Pack
    1778       tmp.Rects = buf_rects + buf_rects_n;
    1779       tmp.RectsCount = font_glyphs_count;
    1780       buf_rects_n += font_glyphs_count;
    1781       stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
    1782       int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
    1783       IM_ASSERT(n == font_glyphs_count);
    1784       stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
    1785 
    1786       // Extend texture height
    1787       for (int i = 0; i < n; i++)
    1788          if (tmp.Rects[i].was_packed)
    1789             atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
    1790    }
    1791    IM_ASSERT(buf_rects_n == total_glyphs_count);
    1792    IM_ASSERT(buf_packedchars_n == total_glyphs_count);
    1793    IM_ASSERT(buf_ranges_n == total_ranges_count);
    1794 
    1795    // Create texture
    1796    atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
    1797    atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
    1798    atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
    1799    memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
    1800    spc.pixels = atlas->TexPixelsAlpha8;
    1801    spc.height = atlas->TexHeight;
    1802 
    1803    // Second pass: render font characters
    1804    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
    1805    {
    1806       ImFontConfig& cfg = atlas->ConfigData[input_i];
    1807       ImFontTempBuildData& tmp = tmp_array[input_i];
    1808       stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
    1809       stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
    1810       if (cfg.RasterizerMultiply != 1.0f)
    1811       {
    1812          unsigned char multiply_table[256];
    1813          ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
    1814          for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++)
    1815             if (r->was_packed)
    1816                ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes);
    1817       }
    1818       tmp.Rects = NULL;
    1819    }
    1820 
    1821    // End packing
    1822    stbtt_PackEnd(&spc);
    1823    ImGui::MemFree(buf_rects);
    1824    buf_rects = NULL;
    1825 
    1826    // Third pass: setup ImFont and glyphs for runtime
    1827    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
    1828    {
    1829       ImFontConfig& cfg = atlas->ConfigData[input_i];
    1830       ImFontTempBuildData& tmp = tmp_array[input_i];
    1831       ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
    1832       if (cfg.MergeMode)
    1833          dst_font->BuildLookupTable();
    1834 
    1835       const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels);
    1836       int unscaled_ascent, unscaled_descent, unscaled_line_gap;
    1837       stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
    1838 
    1839       const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
    1840       const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
    1841       ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
    1842       const float off_x = cfg.GlyphOffset.x;
    1843       const float off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
    1844 
    1845       for (int i = 0; i < tmp.RangesCount; i++)
    1846       {
    1847          stbtt_pack_range& range = tmp.Ranges[i];
    1848          for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1)
    1849          {
    1850             const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
    1851             if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
    1852                continue;
    1853 
    1854             const int codepoint = range.first_unicode_codepoint_in_range + char_idx;
    1855             if (cfg.MergeMode && dst_font->FindGlyphNoFallback((unsigned short)codepoint))
    1856                continue;
    1857 
     2080    IM_ASSERT(atlas->ConfigData.Size > 0);
     2081
     2082    ImFontAtlasBuildInit(atlas);
     2083
     2084    // Clear atlas
     2085    atlas->TexID = (ImTextureID)NULL;
     2086    atlas->TexWidth = atlas->TexHeight = 0;
     2087    atlas->TexUvScale = ImVec2(0.0f, 0.0f);
     2088    atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
     2089    atlas->ClearTexData();
     2090
     2091    // Temporary storage for building
     2092    ImVector<ImFontBuildSrcData> src_tmp_array;
     2093    ImVector<ImFontBuildDstData> dst_tmp_array;
     2094    src_tmp_array.resize(atlas->ConfigData.Size);
     2095    dst_tmp_array.resize(atlas->Fonts.Size);
     2096    memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
     2097    memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
     2098
     2099    // 1. Initialize font loading structure, check font data validity
     2100    for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
     2101    {
     2102        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
     2103        ImFontConfig& cfg = atlas->ConfigData[src_i];
     2104        IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
     2105
     2106        // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
     2107        src_tmp.DstIndex = -1;
     2108        for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
     2109            if (cfg.DstFont == atlas->Fonts[output_i])
     2110                src_tmp.DstIndex = output_i;
     2111        IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
     2112        if (src_tmp.DstIndex == -1)
     2113            return false;
     2114
     2115        // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
     2116        const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
     2117        IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
     2118        if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
     2119            return false;
     2120
     2121        // Measure highest codepoints
     2122        ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
     2123        src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
     2124        for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
     2125            src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
     2126        dst_tmp.SrcCount++;
     2127        dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
     2128    }
     2129
     2130    // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
     2131    int total_glyphs_count = 0;
     2132    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
     2133    {
     2134        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
     2135        ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
     2136        src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);
     2137        if (dst_tmp.GlyphsSet.Storage.empty())
     2138            dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);
     2139
     2140        for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
     2141            for (unsigned int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
     2142            {
     2143                if (dst_tmp.GlyphsSet.TestBit(codepoint))    // Don't overwrite existing glyphs. We could make this an option for MergeMode (e.g. MergeOverwrite==true)
     2144                    continue;
     2145                if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint))    // It is actually in the font?
     2146                    continue;
     2147
     2148                // Add to avail set/counters
     2149                src_tmp.GlyphsCount++;
     2150                dst_tmp.GlyphsCount++;
     2151                src_tmp.GlyphsSet.SetBit(codepoint);
     2152                dst_tmp.GlyphsSet.SetBit(codepoint);
     2153                total_glyphs_count++;
     2154            }
     2155    }
     2156
     2157    // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
     2158    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
     2159    {
     2160        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
     2161        src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
     2162        UnpackBitVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList);
     2163        src_tmp.GlyphsSet.Clear();
     2164        IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
     2165    }
     2166    for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
     2167        dst_tmp_array[dst_i].GlyphsSet.Clear();
     2168    dst_tmp_array.clear();
     2169
     2170    // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
     2171    // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
     2172    ImVector<stbrp_rect> buf_rects;
     2173    ImVector<stbtt_packedchar> buf_packedchars;
     2174    buf_rects.resize(total_glyphs_count);
     2175    buf_packedchars.resize(total_glyphs_count);
     2176    memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
     2177    memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes());
     2178
     2179    // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
     2180    int total_surface = 0;
     2181    int buf_rects_out_n = 0;
     2182    int buf_packedchars_out_n = 0;
     2183    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
     2184    {
     2185        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
     2186        if (src_tmp.GlyphsCount == 0)
     2187            continue;
     2188
     2189        src_tmp.Rects = &buf_rects[buf_rects_out_n];
     2190        src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n];
     2191        buf_rects_out_n += src_tmp.GlyphsCount;
     2192        buf_packedchars_out_n += src_tmp.GlyphsCount;
     2193
     2194        // Convert our ranges in the format stb_truetype wants
     2195        ImFontConfig& cfg = atlas->ConfigData[src_i];
     2196        src_tmp.PackRange.font_size = cfg.SizePixels;
     2197        src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
     2198        src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
     2199        src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
     2200        src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;
     2201        src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;
     2202        src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
     2203
     2204        // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
     2205        const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels);
     2206        const int padding = atlas->TexGlyphPadding;
     2207        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
     2208        {
     2209            int x0, y0, x1, y1;
     2210            const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);
     2211            IM_ASSERT(glyph_index_in_font != 0);
     2212            stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);
     2213            src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1);
     2214            src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1);
     2215            total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
     2216        }
     2217    }
     2218
     2219    // We need a width for the skyline algorithm, any width!
     2220    // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
     2221    // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
     2222    const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
     2223    atlas->TexHeight = 0;
     2224    if (atlas->TexDesiredWidth > 0)
     2225        atlas->TexWidth = atlas->TexDesiredWidth;
     2226    else
     2227        atlas->TexWidth = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;
     2228
     2229    // 5. Start packing
     2230    // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
     2231    const int TEX_HEIGHT_MAX = 1024 * 32;
     2232    stbtt_pack_context spc = {};
     2233    stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL);
     2234    ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
     2235
     2236    // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
     2237    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
     2238    {
     2239        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
     2240        if (src_tmp.GlyphsCount == 0)
     2241            continue;
     2242
     2243        stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount);
     2244
     2245        // Extend texture height and mark missing glyphs as non-packed so we won't render them.
     2246        // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
     2247        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
     2248            if (src_tmp.Rects[glyph_i].was_packed)
     2249                atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
     2250    }
     2251
     2252    // 7. Allocate texture
     2253    atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
     2254    atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
     2255    atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight);
     2256    memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight);
     2257    spc.pixels = atlas->TexPixelsAlpha8;
     2258    spc.height = atlas->TexHeight;
     2259
     2260    // 8. Render/rasterize font characters into the texture
     2261    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
     2262    {
     2263        ImFontConfig& cfg = atlas->ConfigData[src_i];
     2264        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
     2265        if (src_tmp.GlyphsCount == 0)
     2266            continue;
     2267
     2268        stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
     2269
     2270        // Apply multiply operator
     2271        if (cfg.RasterizerMultiply != 1.0f)
     2272        {
     2273            unsigned char multiply_table[256];
     2274            ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
     2275            stbrp_rect* r = &src_tmp.Rects[0];
     2276            for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
     2277                if (r->was_packed)
     2278                    ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1);
     2279        }
     2280        src_tmp.Rects = NULL;
     2281    }
     2282
     2283    // End packing
     2284    stbtt_PackEnd(&spc);
     2285    buf_rects.clear();
     2286
     2287    // 9. Setup ImFont and glyphs for runtime
     2288    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
     2289    {
     2290        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
     2291        if (src_tmp.GlyphsCount == 0)
     2292            continue;
     2293
     2294        // When merging fonts with MergeMode=true:
     2295        // - We can have multiple input fonts writing into a same destination font.
     2296        // - dst_font->ConfigData is != from cfg which is our source configuration.
     2297        ImFontConfig& cfg = atlas->ConfigData[src_i];
     2298        ImFont* dst_font = cfg.DstFont;
     2299
     2300        const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
     2301        int unscaled_ascent, unscaled_descent, unscaled_line_gap;
     2302        stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
     2303
     2304        const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
     2305        const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
     2306        ImFontAtlasBuildSetupFont(atlas, dst_font, &cfg, ascent, descent);
     2307        const float font_off_x = cfg.GlyphOffset.x;
     2308        const float font_off_y = cfg.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
     2309
     2310        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
     2311        {
     2312            // Register glyph
     2313            const int codepoint = src_tmp.GlyphsList[glyph_i];
     2314            const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i];
    18582315            stbtt_aligned_quad q;
    1859             float dummy_x = 0.0f, dummy_y = 0.0f;
    1860             stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
    1861             dst_font->AddGlyph((ImWchar)codepoint, q.x0 + off_x, q.y0 + off_y, q.x1 + off_x, q.y1 + off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance);
    1862          }
    1863       }
    1864    }
    1865 
    1866    // Cleanup temporaries
    1867    ImGui::MemFree(buf_packedchars);
    1868    ImGui::MemFree(buf_ranges);
    1869    ImGui::MemFree(tmp_array);
    1870 
    1871    ImFontAtlasBuildFinish(atlas);
    1872 
    1873    return true;
    1874 }
    1875 
    1876 void ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas)
    1877 {
    1878    if (atlas->CustomRectIds[0] >= 0)
    1879       return;
    1880    if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
    1881       atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
    1882    else
    1883       atlas->CustomRectIds[0] = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_ID, 2, 2);
     2316            float unused_x = 0.0f, unused_y = 0.0f;
     2317            stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &unused_x, &unused_y, &q, 0);
     2318            dst_font->AddGlyph(&cfg, (ImWchar)codepoint, q.x0 + font_off_x, q.y0 + font_off_y, q.x1 + font_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, pc.xadvance);
     2319        }
     2320    }
     2321
     2322    // Cleanup temporary (ImVector doesn't honor destructor)
     2323    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
     2324        src_tmp_array[src_i].~ImFontBuildSrcData();
     2325
     2326    ImFontAtlasBuildFinish(atlas);
     2327    return true;
    18842328}
    18852329
    18862330void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent)
    18872331{
    1888    if (!font_config->MergeMode)
    1889    {
    1890       font->ClearOutputData();
    1891       font->FontSize = font_config->SizePixels;
    1892       font->ConfigData = font_config;
    1893       font->ContainerAtlas = atlas;
    1894       font->Ascent = ascent;
    1895       font->Descent = descent;
    1896    }
    1897    font->ConfigDataCount++;
    1898 }
    1899 
    1900 void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque)
    1901 {
    1902    stbrp_context* pack_context = (stbrp_context*)pack_context_opaque;
    1903 
    1904    ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
    1905    IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
    1906 
    1907    ImVector<stbrp_rect> pack_rects;
    1908    pack_rects.resize(user_rects.Size);
    1909    memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size);
    1910    for (int i = 0; i < user_rects.Size; i++)
    1911    {
    1912       pack_rects[i].w = user_rects[i].Width;
    1913       pack_rects[i].h = user_rects[i].Height;
    1914    }
    1915    stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size);
    1916    for (int i = 0; i < pack_rects.Size; i++)
    1917       if (pack_rects[i].was_packed)
    1918       {
    1919          user_rects[i].X = pack_rects[i].x;
    1920          user_rects[i].Y = pack_rects[i].y;
    1921          IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
    1922          atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
    1923       }
     2332    if (!font_config->MergeMode)
     2333    {
     2334        font->ClearOutputData();
     2335        font->FontSize = font_config->SizePixels;
     2336        font->ConfigData = font_config;
     2337        font->ConfigDataCount = 0;
     2338        font->ContainerAtlas = atlas;
     2339        font->Ascent = ascent;
     2340        font->Descent = descent;
     2341    }
     2342    font->ConfigDataCount++;
     2343}
     2344
     2345void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
     2346{
     2347    stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
     2348    IM_ASSERT(pack_context != NULL);
     2349
     2350    ImVector<ImFontAtlasCustomRect>& user_rects = atlas->CustomRects;
     2351    IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
     2352
     2353    ImVector<stbrp_rect> pack_rects;
     2354    pack_rects.resize(user_rects.Size);
     2355    memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes());
     2356    for (int i = 0; i < user_rects.Size; i++)
     2357    {
     2358        pack_rects[i].w = user_rects[i].Width;
     2359        pack_rects[i].h = user_rects[i].Height;
     2360    }
     2361    stbrp_pack_rects(pack_context, &pack_rects[0], pack_rects.Size);
     2362    for (int i = 0; i < pack_rects.Size; i++)
     2363        if (pack_rects[i].was_packed)
     2364        {
     2365            user_rects[i].X = pack_rects[i].x;
     2366            user_rects[i].Y = pack_rects[i].y;
     2367            IM_ASSERT(pack_rects[i].w == user_rects[i].Width && pack_rects[i].h == user_rects[i].Height);
     2368            atlas->TexHeight = ImMax(atlas->TexHeight, pack_rects[i].y + pack_rects[i].h);
     2369        }
     2370}
     2371
     2372void ImFontAtlasBuildRender1bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value)
     2373{
     2374    IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth);
     2375    IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight);
     2376    unsigned char* out_pixel = atlas->TexPixelsAlpha8 + x + (y * atlas->TexWidth);
     2377    for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w)
     2378        for (int off_x = 0; off_x < w; off_x++)
     2379            out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00;
    19242380}
    19252381
    19262382static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
    19272383{
    1928    IM_ASSERT(atlas->CustomRectIds[0] >= 0);
    1929    IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
    1930    ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]];
    1931    IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
    1932    IM_ASSERT(r.IsPacked());
    1933 
    1934    const int w = atlas->TexWidth;
    1935    if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
    1936    {
    1937       // Render/copy pixels
    1938       IM_ASSERT(r.Width == FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF * 2 + 1 && r.Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);
    1939       for (int y = 0, n = 0; y < FONT_ATLAS_DEFAULT_TEX_DATA_H; y++)
    1940          for (int x = 0; x < FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF; x++, n++)
    1941          {
    1942             const int offset0 = (int)(r.X + x) + (int)(r.Y + y) * w;
    1943             const int offset1 = offset0 + FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF + 1;
    1944             atlas->TexPixelsAlpha8[offset0] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == '.' ? 0xFF : 0x00;
    1945             atlas->TexPixelsAlpha8[offset1] = FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[n] == 'X' ? 0xFF : 0x00;
    1946          }
    1947    }
    1948    else
    1949    {
    1950       IM_ASSERT(r.Width == 2 && r.Height == 2);
    1951       const int offset = (int)(r.X) + (int)(r.Y) * w;
    1952       atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF;
    1953    }
    1954    atlas->TexUvWhitePixel = ImVec2((r.X + 0.5f) * atlas->TexUvScale.x, (r.Y + 0.5f) * atlas->TexUvScale.y);
    1955 }
    1956 
     2384    ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors);
     2385    IM_ASSERT(r->IsPacked());
     2386
     2387    const int w = atlas->TexWidth;
     2388    if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
     2389    {
     2390        // Render/copy pixels
     2391        IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H);
     2392        const int x_for_white = r->X;
     2393        const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1;
     2394        ImFontAtlasBuildRender1bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF);
     2395        ImFontAtlasBuildRender1bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF);
     2396    }
     2397    else
     2398    {
     2399        // Render 4 white pixels
     2400        IM_ASSERT(r->Width == 2 && r->Height == 2);
     2401        const int offset = (int)r->X + (int)r->Y * w;
     2402        atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF;
     2403    }
     2404    atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y);
     2405}
     2406
     2407static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas)
     2408{
     2409    if (atlas->Flags & ImFontAtlasFlags_NoBakedLines)
     2410        return;
     2411
     2412    // This generates a triangular shape in the texture, with the various line widths stacked on top of each other to allow interpolation between them
     2413    ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdLines);
     2414    IM_ASSERT(r->IsPacked());
     2415    for (unsigned int n = 0; n < IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1; n++) // +1 because of the zero-width row
     2416    {
     2417        // Each line consists of at least two empty pixels at the ends, with a line of solid pixels in the middle
     2418        unsigned int y = n;
     2419        unsigned int line_width = n;
     2420        unsigned int pad_left = (r->Width - line_width) / 2;
     2421        unsigned int pad_right = r->Width - (pad_left + line_width);
     2422
     2423        // Write each slice
     2424        IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels
     2425        unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)];
     2426        memset(write_ptr, 0x00, pad_left);
     2427        memset(write_ptr + pad_left, 0xFF, line_width);
     2428        memset(write_ptr + pad_left + line_width, 0x00, pad_right);
     2429
     2430        // Calculate UVs for this line
     2431        ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale;
     2432        ImVec2 uv1 = ImVec2((float)(r->X + pad_left + line_width + 1), (float)(r->Y + y + 1)) * atlas->TexUvScale;
     2433        float half_v = (uv0.y + uv1.y) * 0.5f; // Calculate a constant V in the middle of the row to avoid sampling artifacts
     2434        atlas->TexUvLines[n] = ImVec4(uv0.x, half_v, uv1.x, half_v);
     2435    }
     2436}
     2437
     2438// Note: this is called / shared by both the stb_truetype and the FreeType builder
     2439void ImFontAtlasBuildInit(ImFontAtlas* atlas)
     2440{
     2441    // Register texture region for mouse cursors or standard white pixels
     2442    if (atlas->PackIdMouseCursors < 0)
     2443    {
     2444        if (!(atlas->Flags & ImFontAtlasFlags_NoMouseCursors))
     2445            atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1, FONT_ATLAS_DEFAULT_TEX_DATA_H);
     2446        else
     2447            atlas->PackIdMouseCursors = atlas->AddCustomRectRegular(2, 2);
     2448    }
     2449
     2450    // Register texture region for thick lines
     2451    // The +2 here is to give space for the end caps, whilst height +1 is to accommodate the fact we have a zero-width row
     2452    if (atlas->PackIdLines < 0)
     2453    {
     2454        if (!(atlas->Flags & ImFontAtlasFlags_NoBakedLines))
     2455            atlas->PackIdLines = atlas->AddCustomRectRegular(IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 2, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1);
     2456    }
     2457}
     2458
     2459// This is called/shared by both the stb_truetype and the FreeType builder.
    19572460void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
    19582461{
    1959    // Render into our custom data block
    1960    ImFontAtlasBuildRenderDefaultTexData(atlas);
    1961 
    1962    // Register custom rectangle glyphs
    1963    for (int i = 0; i < atlas->CustomRects.Size; i++)
    1964    {
    1965       const ImFontAtlas::CustomRect& r = atlas->CustomRects[i];
    1966       if (r.Font == NULL || r.ID > 0x10000)
    1967          continue;
    1968 
    1969       IM_ASSERT(r.Font->ContainerAtlas == atlas);
    1970       ImVec2 uv0, uv1;
    1971       atlas->CalcCustomRectUV(&r, &uv0, &uv1);
    1972       r.Font->AddGlyph((ImWchar)r.ID, r.GlyphOffset.x, r.GlyphOffset.y, r.GlyphOffset.x + r.Width, r.GlyphOffset.y + r.Height, uv0.x, uv0.y, uv1.x, uv1.y, r.GlyphAdvanceX);
    1973    }
    1974 
    1975    // Build all fonts lookup tables
    1976    for (int i = 0; i < atlas->Fonts.Size; i++)
    1977       if (atlas->Fonts[i]->DirtyLookupTables)
    1978          atlas->Fonts[i]->BuildLookupTable();
     2462    // Render into our custom data blocks
     2463    IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
     2464    ImFontAtlasBuildRenderDefaultTexData(atlas);
     2465    ImFontAtlasBuildRenderLinesTexData(atlas);
     2466
     2467    // Register custom rectangle glyphs
     2468    for (int i = 0; i < atlas->CustomRects.Size; i++)
     2469    {
     2470        const ImFontAtlasCustomRect* r = &atlas->CustomRects[i];
     2471        if (r->Font == NULL || r->GlyphID == 0)
     2472            continue;
     2473
     2474        // Will ignore ImFontConfig settings: GlyphMinAdvanceX, GlyphMinAdvanceY, GlyphExtraSpacing, PixelSnapH
     2475        IM_ASSERT(r->Font->ContainerAtlas == atlas);
     2476        ImVec2 uv0, uv1;
     2477        atlas->CalcCustomRectUV(r, &uv0, &uv1);
     2478        r->Font->AddGlyph(NULL, (ImWchar)r->GlyphID, r->GlyphOffset.x, r->GlyphOffset.y, r->GlyphOffset.x + r->Width, r->GlyphOffset.y + r->Height, uv0.x, uv0.y, uv1.x, uv1.y, r->GlyphAdvanceX);
     2479    }
     2480
     2481    // Build all fonts lookup tables
     2482    for (int i = 0; i < atlas->Fonts.Size; i++)
     2483        if (atlas->Fonts[i]->DirtyLookupTables)
     2484            atlas->Fonts[i]->BuildLookupTable();
     2485
     2486    // Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
     2487    // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
     2488    // FIXME: Also note that 0x2026 is currently seldom included in our font ranges. Because of this we are more likely to use three individual dots.
     2489    for (int i = 0; i < atlas->Fonts.size(); i++)
     2490    {
     2491        ImFont* font = atlas->Fonts[i];
     2492        if (font->EllipsisChar != (ImWchar)-1)
     2493            continue;
     2494        const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
     2495        for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++)
     2496            if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) // Verify glyph exists
     2497            {
     2498                font->EllipsisChar = ellipsis_variants[j];
     2499                break;
     2500            }
     2501    }
    19792502}
    19802503
     
    19822505const ImWchar*   ImFontAtlas::GetGlyphRangesDefault()
    19832506{
    1984    static const ImWchar ranges[] =
    1985    {
    1986       0x0020, 0x00FF, // Basic Latin + Latin Supplement
    1987       0,
    1988    };
    1989    return &ranges[0];
     2507    static const ImWchar ranges[] =
     2508    {
     2509        0x0020, 0x00FF, // Basic Latin + Latin Supplement
     2510        0,
     2511    };
     2512    return &ranges[0];
    19902513}
    19912514
    19922515const ImWchar*  ImFontAtlas::GetGlyphRangesKorean()
    19932516{
    1994    static const ImWchar ranges[] =
    1995    {
    1996       0x0020, 0x00FF, // Basic Latin + Latin Supplement
    1997       0x3131, 0x3163, // Korean alphabets
    1998       0xAC00, 0xD79D, // Korean characters
    1999       0,
    2000    };
    2001    return &ranges[0];
    2002 }
    2003 
    2004 const ImWchar*  ImFontAtlas::GetGlyphRangesChinese()
    2005 {
    2006    static const ImWchar ranges[] =
    2007    {
    2008       0x0020, 0x00FF, // Basic Latin + Latin Supplement
    2009       0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
    2010       0x31F0, 0x31FF, // Katakana Phonetic Extensions
    2011       0xFF00, 0xFFEF, // Half-width characters
    2012       0x4e00, 0x9FAF, // CJK Ideograms
    2013       0,
    2014    };
    2015    return &ranges[0];
     2517    static const ImWchar ranges[] =
     2518    {
     2519        0x0020, 0x00FF, // Basic Latin + Latin Supplement
     2520        0x3131, 0x3163, // Korean alphabets
     2521        0xAC00, 0xD7A3, // Korean characters
     2522        0,
     2523    };
     2524    return &ranges[0];
     2525}
     2526
     2527const ImWchar*  ImFontAtlas::GetGlyphRangesChineseFull()
     2528{
     2529    static const ImWchar ranges[] =
     2530    {
     2531        0x0020, 0x00FF, // Basic Latin + Latin Supplement
     2532        0x2000, 0x206F, // General Punctuation
     2533        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
     2534        0x31F0, 0x31FF, // Katakana Phonetic Extensions
     2535        0xFF00, 0xFFEF, // Half-width characters
     2536        0x4e00, 0x9FAF, // CJK Ideograms
     2537        0,
     2538    };
     2539    return &ranges[0];
     2540}
     2541
     2542static void UnpackAccumulativeOffsetsIntoRanges(int base_codepoint, const short* accumulative_offsets, int accumulative_offsets_count, ImWchar* out_ranges)
     2543{
     2544    for (int n = 0; n < accumulative_offsets_count; n++, out_ranges += 2)
     2545    {
     2546        out_ranges[0] = out_ranges[1] = (ImWchar)(base_codepoint + accumulative_offsets[n]);
     2547        base_codepoint += accumulative_offsets[n];
     2548    }
     2549    out_ranges[0] = 0;
     2550}
     2551
     2552//-------------------------------------------------------------------------
     2553// [SECTION] ImFontAtlas glyph ranges helpers
     2554//-------------------------------------------------------------------------
     2555
     2556const ImWchar*  ImFontAtlas::GetGlyphRangesChineseSimplifiedCommon()
     2557{
     2558    // Store 2500 regularly used characters for Simplified Chinese.
     2559    // Sourced from https://zh.wiktionary.org/wiki/%E9%99%84%E5%BD%95:%E7%8E%B0%E4%BB%A3%E6%B1%89%E8%AF%AD%E5%B8%B8%E7%94%A8%E5%AD%97%E8%A1%A8
     2560    // This table covers 97.97% of all characters used during the month in July, 1987.
     2561    // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
     2562    // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
     2563    static const short accumulative_offsets_from_0x4E00[] =
     2564    {
     2565        0,1,2,4,1,1,1,1,2,1,3,2,1,2,2,1,1,1,1,1,5,2,1,2,3,3,3,2,2,4,1,1,1,2,1,5,2,3,1,2,1,2,1,1,2,1,1,2,2,1,4,1,1,1,1,5,10,1,2,19,2,1,2,1,2,1,2,1,2,
     2566        1,5,1,6,3,2,1,2,2,1,1,1,4,8,5,1,1,4,1,1,3,1,2,1,5,1,2,1,1,1,10,1,1,5,2,4,6,1,4,2,2,2,12,2,1,1,6,1,1,1,4,1,1,4,6,5,1,4,2,2,4,10,7,1,1,4,2,4,
     2567        2,1,4,3,6,10,12,5,7,2,14,2,9,1,1,6,7,10,4,7,13,1,5,4,8,4,1,1,2,28,5,6,1,1,5,2,5,20,2,2,9,8,11,2,9,17,1,8,6,8,27,4,6,9,20,11,27,6,68,2,2,1,1,
     2568        1,2,1,2,2,7,6,11,3,3,1,1,3,1,2,1,1,1,1,1,3,1,1,8,3,4,1,5,7,2,1,4,4,8,4,2,1,2,1,1,4,5,6,3,6,2,12,3,1,3,9,2,4,3,4,1,5,3,3,1,3,7,1,5,1,1,1,1,2,
     2569        3,4,5,2,3,2,6,1,1,2,1,7,1,7,3,4,5,15,2,2,1,5,3,22,19,2,1,1,1,1,2,5,1,1,1,6,1,1,12,8,2,9,18,22,4,1,1,5,1,16,1,2,7,10,15,1,1,6,2,4,1,2,4,1,6,
     2570        1,1,3,2,4,1,6,4,5,1,2,1,1,2,1,10,3,1,3,2,1,9,3,2,5,7,2,19,4,3,6,1,1,1,1,1,4,3,2,1,1,1,2,5,3,1,1,1,2,2,1,1,2,1,1,2,1,3,1,1,1,3,7,1,4,1,1,2,1,
     2571        1,2,1,2,4,4,3,8,1,1,1,2,1,3,5,1,3,1,3,4,6,2,2,14,4,6,6,11,9,1,15,3,1,28,5,2,5,5,3,1,3,4,5,4,6,14,3,2,3,5,21,2,7,20,10,1,2,19,2,4,28,28,2,3,
     2572        2,1,14,4,1,26,28,42,12,40,3,52,79,5,14,17,3,2,2,11,3,4,6,3,1,8,2,23,4,5,8,10,4,2,7,3,5,1,1,6,3,1,2,2,2,5,28,1,1,7,7,20,5,3,29,3,17,26,1,8,4,
     2573        27,3,6,11,23,5,3,4,6,13,24,16,6,5,10,25,35,7,3,2,3,3,14,3,6,2,6,1,4,2,3,8,2,1,1,3,3,3,4,1,1,13,2,2,4,5,2,1,14,14,1,2,2,1,4,5,2,3,1,14,3,12,
     2574        3,17,2,16,5,1,2,1,8,9,3,19,4,2,2,4,17,25,21,20,28,75,1,10,29,103,4,1,2,1,1,4,2,4,1,2,3,24,2,2,2,1,1,2,1,3,8,1,1,1,2,1,1,3,1,1,1,6,1,5,3,1,1,
     2575        1,3,4,1,1,5,2,1,5,6,13,9,16,1,1,1,1,3,2,3,2,4,5,2,5,2,2,3,7,13,7,2,2,1,1,1,1,2,3,3,2,1,6,4,9,2,1,14,2,14,2,1,18,3,4,14,4,11,41,15,23,15,23,
     2576        176,1,3,4,1,1,1,1,5,3,1,2,3,7,3,1,1,2,1,2,4,4,6,2,4,1,9,7,1,10,5,8,16,29,1,1,2,2,3,1,3,5,2,4,5,4,1,1,2,2,3,3,7,1,6,10,1,17,1,44,4,6,2,1,1,6,
     2577        5,4,2,10,1,6,9,2,8,1,24,1,2,13,7,8,8,2,1,4,1,3,1,3,3,5,2,5,10,9,4,9,12,2,1,6,1,10,1,1,7,7,4,10,8,3,1,13,4,3,1,6,1,3,5,2,1,2,17,16,5,2,16,6,
     2578        1,4,2,1,3,3,6,8,5,11,11,1,3,3,2,4,6,10,9,5,7,4,7,4,7,1,1,4,2,1,3,6,8,7,1,6,11,5,5,3,24,9,4,2,7,13,5,1,8,82,16,61,1,1,1,4,2,2,16,10,3,8,1,1,
     2579        6,4,2,1,3,1,1,1,4,3,8,4,2,2,1,1,1,1,1,6,3,5,1,1,4,6,9,2,1,1,1,2,1,7,2,1,6,1,5,4,4,3,1,8,1,3,3,1,3,2,2,2,2,3,1,6,1,2,1,2,1,3,7,1,8,2,1,2,1,5,
     2580        2,5,3,5,10,1,2,1,1,3,2,5,11,3,9,3,5,1,1,5,9,1,2,1,5,7,9,9,8,1,3,3,3,6,8,2,3,2,1,1,32,6,1,2,15,9,3,7,13,1,3,10,13,2,14,1,13,10,2,1,3,10,4,15,
     2581        2,15,15,10,1,3,9,6,9,32,25,26,47,7,3,2,3,1,6,3,4,3,2,8,5,4,1,9,4,2,2,19,10,6,2,3,8,1,2,2,4,2,1,9,4,4,4,6,4,8,9,2,3,1,1,1,1,3,5,5,1,3,8,4,6,
     2582        2,1,4,12,1,5,3,7,13,2,5,8,1,6,1,2,5,14,6,1,5,2,4,8,15,5,1,23,6,62,2,10,1,1,8,1,2,2,10,4,2,2,9,2,1,1,3,2,3,1,5,3,3,2,1,3,8,1,1,1,11,3,1,1,4,
     2583        3,7,1,14,1,2,3,12,5,2,5,1,6,7,5,7,14,11,1,3,1,8,9,12,2,1,11,8,4,4,2,6,10,9,13,1,1,3,1,5,1,3,2,4,4,1,18,2,3,14,11,4,29,4,2,7,1,3,13,9,2,2,5,
     2584        3,5,20,7,16,8,5,72,34,6,4,22,12,12,28,45,36,9,7,39,9,191,1,1,1,4,11,8,4,9,2,3,22,1,1,1,1,4,17,1,7,7,1,11,31,10,2,4,8,2,3,2,1,4,2,16,4,32,2,
     2585        3,19,13,4,9,1,5,2,14,8,1,1,3,6,19,6,5,1,16,6,2,10,8,5,1,2,3,1,5,5,1,11,6,6,1,3,3,2,6,3,8,1,1,4,10,7,5,7,7,5,8,9,2,1,3,4,1,1,3,1,3,3,2,6,16,
     2586        1,4,6,3,1,10,6,1,3,15,2,9,2,10,25,13,9,16,6,2,2,10,11,4,3,9,1,2,6,6,5,4,30,40,1,10,7,12,14,33,6,3,6,7,3,1,3,1,11,14,4,9,5,12,11,49,18,51,31,
     2587        140,31,2,2,1,5,1,8,1,10,1,4,4,3,24,1,10,1,3,6,6,16,3,4,5,2,1,4,2,57,10,6,22,2,22,3,7,22,6,10,11,36,18,16,33,36,2,5,5,1,1,1,4,10,1,4,13,2,7,
     2588        5,2,9,3,4,1,7,43,3,7,3,9,14,7,9,1,11,1,1,3,7,4,18,13,1,14,1,3,6,10,73,2,2,30,6,1,11,18,19,13,22,3,46,42,37,89,7,3,16,34,2,2,3,9,1,7,1,1,1,2,
     2589        2,4,10,7,3,10,3,9,5,28,9,2,6,13,7,3,1,3,10,2,7,2,11,3,6,21,54,85,2,1,4,2,2,1,39,3,21,2,2,5,1,1,1,4,1,1,3,4,15,1,3,2,4,4,2,3,8,2,20,1,8,7,13,
     2590        4,1,26,6,2,9,34,4,21,52,10,4,4,1,5,12,2,11,1,7,2,30,12,44,2,30,1,1,3,6,16,9,17,39,82,2,2,24,7,1,7,3,16,9,14,44,2,1,2,1,2,3,5,2,4,1,6,7,5,3,
     2591        2,6,1,11,5,11,2,1,18,19,8,1,3,24,29,2,1,3,5,2,2,1,13,6,5,1,46,11,3,5,1,1,5,8,2,10,6,12,6,3,7,11,2,4,16,13,2,5,1,1,2,2,5,2,28,5,2,23,10,8,4,
     2592        4,22,39,95,38,8,14,9,5,1,13,5,4,3,13,12,11,1,9,1,27,37,2,5,4,4,63,211,95,2,2,2,1,3,5,2,1,1,2,2,1,1,1,3,2,4,1,2,1,1,5,2,2,1,1,2,3,1,3,1,1,1,
     2593        3,1,4,2,1,3,6,1,1,3,7,15,5,3,2,5,3,9,11,4,2,22,1,6,3,8,7,1,4,28,4,16,3,3,25,4,4,27,27,1,4,1,2,2,7,1,3,5,2,28,8,2,14,1,8,6,16,25,3,3,3,14,3,
     2594        3,1,1,2,1,4,6,3,8,4,1,1,1,2,3,6,10,6,2,3,18,3,2,5,5,4,3,1,5,2,5,4,23,7,6,12,6,4,17,11,9,5,1,1,10,5,12,1,1,11,26,33,7,3,6,1,17,7,1,5,12,1,11,
     2595        2,4,1,8,14,17,23,1,2,1,7,8,16,11,9,6,5,2,6,4,16,2,8,14,1,11,8,9,1,1,1,9,25,4,11,19,7,2,15,2,12,8,52,7,5,19,2,16,4,36,8,1,16,8,24,26,4,6,2,9,
     2596        5,4,36,3,28,12,25,15,37,27,17,12,59,38,5,32,127,1,2,9,17,14,4,1,2,1,1,8,11,50,4,14,2,19,16,4,17,5,4,5,26,12,45,2,23,45,104,30,12,8,3,10,2,2,
     2597        3,3,1,4,20,7,2,9,6,15,2,20,1,3,16,4,11,15,6,134,2,5,59,1,2,2,2,1,9,17,3,26,137,10,211,59,1,2,4,1,4,1,1,1,2,6,2,3,1,1,2,3,2,3,1,3,4,4,2,3,3,
     2598        1,4,3,1,7,2,2,3,1,2,1,3,3,3,2,2,3,2,1,3,14,6,1,3,2,9,6,15,27,9,34,145,1,1,2,1,1,1,1,2,1,1,1,1,2,2,2,3,1,2,1,1,1,2,3,5,8,3,5,2,4,1,3,2,2,2,12,
     2599        4,1,1,1,10,4,5,1,20,4,16,1,15,9,5,12,2,9,2,5,4,2,26,19,7,1,26,4,30,12,15,42,1,6,8,172,1,1,4,2,1,1,11,2,2,4,2,1,2,1,10,8,1,2,1,4,5,1,2,5,1,8,
     2600        4,1,3,4,2,1,6,2,1,3,4,1,2,1,1,1,1,12,5,7,2,4,3,1,1,1,3,3,6,1,2,2,3,3,3,2,1,2,12,14,11,6,6,4,12,2,8,1,7,10,1,35,7,4,13,15,4,3,23,21,28,52,5,
     2601        26,5,6,1,7,10,2,7,53,3,2,1,1,1,2,163,532,1,10,11,1,3,3,4,8,2,8,6,2,2,23,22,4,2,2,4,2,1,3,1,3,3,5,9,8,2,1,2,8,1,10,2,12,21,20,15,105,2,3,1,1,
     2602        3,2,3,1,1,2,5,1,4,15,11,19,1,1,1,1,5,4,5,1,1,2,5,3,5,12,1,2,5,1,11,1,1,15,9,1,4,5,3,26,8,2,1,3,1,1,15,19,2,12,1,2,5,2,7,2,19,2,20,6,26,7,5,
     2603        2,2,7,34,21,13,70,2,128,1,1,2,1,1,2,1,1,3,2,2,2,15,1,4,1,3,4,42,10,6,1,49,85,8,1,2,1,1,4,4,2,3,6,1,5,7,4,3,211,4,1,2,1,2,5,1,2,4,2,2,6,5,6,
     2604        10,3,4,48,100,6,2,16,296,5,27,387,2,2,3,7,16,8,5,38,15,39,21,9,10,3,7,59,13,27,21,47,5,21,6
     2605    };
     2606    static ImWchar base_ranges[] = // not zero-terminated
     2607    {
     2608        0x0020, 0x00FF, // Basic Latin + Latin Supplement
     2609        0x2000, 0x206F, // General Punctuation
     2610        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
     2611        0x31F0, 0x31FF, // Katakana Phonetic Extensions
     2612        0xFF00, 0xFFEF  // Half-width characters
     2613    };
     2614    static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00) * 2 + 1] = { 0 };
     2615    if (!full_ranges[0])
     2616    {
     2617        memcpy(full_ranges, base_ranges, sizeof(base_ranges));
     2618        UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
     2619    }
     2620    return &full_ranges[0];
    20162621}
    20172622
    20182623const ImWchar*  ImFontAtlas::GetGlyphRangesJapanese()
    20192624{
    2020    // Store the 1946 ideograms code points as successive offsets from the initial unicode codepoint 0x4E00. Each offset has an implicit +1.
    2021    // This encoding is designed to helps us reduce the source code size.
    2022    // FIXME: Source a list of the revised 2136 joyo kanji list from 2010 and rebuild this.
    2023    // The current list was sourced from http://theinstructionlimit.com/author/renaudbedardrenaudbedard/page/3
    2024    // Note that you may use ImFontAtlas::GlyphRangesBuilder to create your own ranges, by merging existing ranges or adding new characters.
    2025    static const short offsets_from_0x4E00[] =
    2026    {
    2027       -1,0,1,3,0,0,0,0,1,0,5,1,1,0,7,4,6,10,0,1,9,9,7,1,3,19,1,10,7,1,0,1,0,5,1,0,6,4,2,6,0,0,12,6,8,0,3,5,0,1,0,9,0,0,8,1,1,3,4,5,13,0,0,8,2,17,
    2028       4,3,1,1,9,6,0,0,0,2,1,3,2,22,1,9,11,1,13,1,3,12,0,5,9,2,0,6,12,5,3,12,4,1,2,16,1,1,4,6,5,3,0,6,13,15,5,12,8,14,0,0,6,15,3,6,0,18,8,1,6,14,1,
    2029       5,4,12,24,3,13,12,10,24,0,0,0,1,0,1,1,2,9,10,2,2,0,0,3,3,1,0,3,8,0,3,2,4,4,1,6,11,10,14,6,15,3,4,15,1,0,0,5,2,2,0,0,1,6,5,5,6,0,3,6,5,0,0,1,0,
    2030       11,2,2,8,4,7,0,10,0,1,2,17,19,3,0,2,5,0,6,2,4,4,6,1,1,11,2,0,3,1,2,1,2,10,7,6,3,16,0,8,24,0,0,3,1,1,3,0,1,6,0,0,0,2,0,1,5,15,0,1,0,0,2,11,19,
    2031       1,4,19,7,6,5,1,0,0,0,0,5,1,0,1,9,0,0,5,0,2,0,1,0,3,0,11,3,0,2,0,0,0,0,0,9,3,6,4,12,0,14,0,0,29,10,8,0,14,37,13,0,31,16,19,0,8,30,1,20,8,3,48,
    2032       21,1,0,12,0,10,44,34,42,54,11,18,82,0,2,1,2,12,1,0,6,2,17,2,12,7,0,7,17,4,2,6,24,23,8,23,39,2,16,23,1,0,5,1,2,15,14,5,6,2,11,0,8,6,2,2,2,14,
    2033       20,4,15,3,4,11,10,10,2,5,2,1,30,2,1,0,0,22,5,5,0,3,1,5,4,1,0,0,2,2,21,1,5,1,2,16,2,1,3,4,0,8,4,0,0,5,14,11,2,16,1,13,1,7,0,22,15,3,1,22,7,14,
    2034       22,19,11,24,18,46,10,20,64,45,3,2,0,4,5,0,1,4,25,1,0,0,2,10,0,0,0,1,0,1,2,0,0,9,1,2,0,0,0,2,5,2,1,1,5,5,8,1,1,1,5,1,4,9,1,3,0,1,0,1,1,2,0,0,
    2035       2,0,1,8,22,8,1,0,0,0,0,4,2,1,0,9,8,5,0,9,1,30,24,2,6,4,39,0,14,5,16,6,26,179,0,2,1,1,0,0,0,5,2,9,6,0,2,5,16,7,5,1,1,0,2,4,4,7,15,13,14,0,0,
    2036       3,0,1,0,0,0,2,1,6,4,5,1,4,9,0,3,1,8,0,0,10,5,0,43,0,2,6,8,4,0,2,0,0,9,6,0,9,3,1,6,20,14,6,1,4,0,7,2,3,0,2,0,5,0,3,1,0,3,9,7,0,3,4,0,4,9,1,6,0,
    2037       9,0,0,2,3,10,9,28,3,6,2,4,1,2,32,4,1,18,2,0,3,1,5,30,10,0,2,2,2,0,7,9,8,11,10,11,7,2,13,7,5,10,0,3,40,2,0,1,6,12,0,4,5,1,5,11,11,21,4,8,3,7,
    2038       8,8,33,5,23,0,0,19,8,8,2,3,0,6,1,1,1,5,1,27,4,2,5,0,3,5,6,3,1,0,3,1,12,5,3,3,2,0,7,7,2,1,0,4,0,1,1,2,0,10,10,6,2,5,9,7,5,15,15,21,6,11,5,20,
    2039       4,3,5,5,2,5,0,2,1,0,1,7,28,0,9,0,5,12,5,5,18,30,0,12,3,3,21,16,25,32,9,3,14,11,24,5,66,9,1,2,0,5,9,1,5,1,8,0,8,3,3,0,1,15,1,4,8,1,2,7,0,7,2,
    2040       8,3,7,5,3,7,10,2,1,0,0,2,25,0,6,4,0,10,0,4,2,4,1,12,5,38,4,0,4,1,10,5,9,4,0,14,4,2,5,18,20,21,1,3,0,5,0,7,0,3,7,1,3,1,1,8,1,0,0,0,3,2,5,2,11,
    2041       6,0,13,1,3,9,1,12,0,16,6,2,1,0,2,1,12,6,13,11,2,0,28,1,7,8,14,13,8,13,0,2,0,5,4,8,10,2,37,42,19,6,6,7,4,14,11,18,14,80,7,6,0,4,72,12,36,27,
    2042       7,7,0,14,17,19,164,27,0,5,10,7,3,13,6,14,0,2,2,5,3,0,6,13,0,0,10,29,0,4,0,3,13,0,3,1,6,51,1,5,28,2,0,8,0,20,2,4,0,25,2,10,13,10,0,16,4,0,1,0,
    2043       2,1,7,0,1,8,11,0,0,1,2,7,2,23,11,6,6,4,16,2,2,2,0,22,9,3,3,5,2,0,15,16,21,2,9,20,15,15,5,3,9,1,0,0,1,7,7,5,4,2,2,2,38,24,14,0,0,15,5,6,24,14,
    2044       5,5,11,0,21,12,0,3,8,4,11,1,8,0,11,27,7,2,4,9,21,59,0,1,39,3,60,62,3,0,12,11,0,3,30,11,0,13,88,4,15,5,28,13,1,4,48,17,17,4,28,32,46,0,16,0,
    2045       18,11,1,8,6,38,11,2,6,11,38,2,0,45,3,11,2,7,8,4,30,14,17,2,1,1,65,18,12,16,4,2,45,123,12,56,33,1,4,3,4,7,0,0,0,3,2,0,16,4,2,4,2,0,7,4,5,2,26,
    2046       2,25,6,11,6,1,16,2,6,17,77,15,3,35,0,1,0,5,1,0,38,16,6,3,12,3,3,3,0,9,3,1,3,5,2,9,0,18,0,25,1,3,32,1,72,46,6,2,7,1,3,14,17,0,28,1,40,13,0,20,
    2047       15,40,6,38,24,12,43,1,1,9,0,12,6,0,6,2,4,19,3,7,1,48,0,9,5,0,5,6,9,6,10,15,2,11,19,3,9,2,0,1,10,1,27,8,1,3,6,1,14,0,26,0,27,16,3,4,9,6,2,23,
    2048       9,10,5,25,2,1,6,1,1,48,15,9,15,14,3,4,26,60,29,13,37,21,1,6,4,0,2,11,22,23,16,16,2,2,1,3,0,5,1,6,4,0,0,4,0,0,8,3,0,2,5,0,7,1,7,3,13,2,4,10,
    2049       3,0,2,31,0,18,3,0,12,10,4,1,0,7,5,7,0,5,4,12,2,22,10,4,2,15,2,8,9,0,23,2,197,51,3,1,1,4,13,4,3,21,4,19,3,10,5,40,0,4,1,1,10,4,1,27,34,7,21,
    2050       2,17,2,9,6,4,2,3,0,4,2,7,8,2,5,1,15,21,3,4,4,2,2,17,22,1,5,22,4,26,7,0,32,1,11,42,15,4,1,2,5,0,19,3,1,8,6,0,10,1,9,2,13,30,8,2,24,17,19,1,4,
    2051       4,25,13,0,10,16,11,39,18,8,5,30,82,1,6,8,18,77,11,13,20,75,11,112,78,33,3,0,0,60,17,84,9,1,1,12,30,10,49,5,32,158,178,5,5,6,3,3,1,3,1,4,7,6,
    2052       19,31,21,0,2,9,5,6,27,4,9,8,1,76,18,12,1,4,0,3,3,6,3,12,2,8,30,16,2,25,1,5,5,4,3,0,6,10,2,3,1,0,5,1,19,3,0,8,1,5,2,6,0,0,0,19,1,2,0,5,1,2,5,
    2053       1,3,7,0,4,12,7,3,10,22,0,9,5,1,0,2,20,1,1,3,23,30,3,9,9,1,4,191,14,3,15,6,8,50,0,1,0,0,4,0,0,1,0,2,4,2,0,2,3,0,2,0,2,2,8,7,0,1,1,1,3,3,17,11,
    2054       91,1,9,3,2,13,4,24,15,41,3,13,3,1,20,4,125,29,30,1,0,4,12,2,21,4,5,5,19,11,0,13,11,86,2,18,0,7,1,8,8,2,2,22,1,2,6,5,2,0,1,2,8,0,2,0,5,2,1,0,
    2055       2,10,2,0,5,9,2,1,2,0,1,0,4,0,0,10,2,5,3,0,6,1,0,1,4,4,33,3,13,17,3,18,6,4,7,1,5,78,0,4,1,13,7,1,8,1,0,35,27,15,3,0,0,0,1,11,5,41,38,15,22,6,
    2056       14,14,2,1,11,6,20,63,5,8,27,7,11,2,2,40,58,23,50,54,56,293,8,8,1,5,1,14,0,1,12,37,89,8,8,8,2,10,6,0,0,0,4,5,2,1,0,1,1,2,7,0,3,3,0,4,6,0,3,2,
    2057       19,3,8,0,0,0,4,4,16,0,4,1,5,1,3,0,3,4,6,2,17,10,10,31,6,4,3,6,10,126,7,3,2,2,0,9,0,0,5,20,13,0,15,0,6,0,2,5,8,64,50,3,2,12,2,9,0,0,11,8,20,
    2058       109,2,18,23,0,0,9,61,3,0,28,41,77,27,19,17,81,5,2,14,5,83,57,252,14,154,263,14,20,8,13,6,57,39,38,
    2059    };
    2060    static ImWchar base_ranges[] =
    2061    {
    2062       0x0020, 0x00FF, // Basic Latin + Latin Supplement
    2063       0x3000, 0x30FF, // Punctuations, Hiragana, Katakana
    2064       0x31F0, 0x31FF, // Katakana Phonetic Extensions
    2065       0xFF00, 0xFFEF, // Half-width characters
    2066    };
    2067    static bool full_ranges_unpacked = false;
    2068    static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(offsets_from_0x4E00) * 2 + 1];
    2069    if (!full_ranges_unpacked)
    2070    {
    2071       // Unpack
    2072       int codepoint = 0x4e00;
    2073       memcpy(full_ranges, base_ranges, sizeof(base_ranges));
    2074       ImWchar* dst = full_ranges + IM_ARRAYSIZE(base_ranges);
    2075       for (int n = 0; n < IM_ARRAYSIZE(offsets_from_0x4E00); n++, dst += 2)
    2076          dst[0] = dst[1] = (ImWchar)(codepoint += (offsets_from_0x4E00[n] + 1));
    2077       dst[0] = 0;
    2078       full_ranges_unpacked = true;
    2079    }
    2080    return &full_ranges[0];
     2625    // 1946 common ideograms code points for Japanese
     2626    // Sourced from http://theinstructionlimit.com/common-kanji-character-ranges-for-xna-spritefont-rendering
     2627    // FIXME: Source a list of the revised 2136 Joyo Kanji list from 2010 and rebuild this.
     2628    // You can use ImFontGlyphRangesBuilder to create your own ranges derived from this, by merging existing ranges or adding new characters.
     2629    // (Stored as accumulative offsets from the initial unicode codepoint 0x4E00. This encoding is designed to helps us compact the source code size.)
     2630    static const short accumulative_offsets_from_0x4E00[] =
     2631    {
     2632        0,1,2,4,1,1,1,1,2,1,6,2,2,1,8,5,7,11,1,2,10,10,8,2,4,20,2,11,8,2,1,2,1,6,2,1,7,5,3,7,1,1,13,7,9,1,4,6,1,2,1,10,1,1,9,2,2,4,5,6,14,1,1,9,3,18,
     2633        5,4,2,2,10,7,1,1,1,3,2,4,3,23,2,10,12,2,14,2,4,13,1,6,10,3,1,7,13,6,4,13,5,2,3,17,2,2,5,7,6,4,1,7,14,16,6,13,9,15,1,1,7,16,4,7,1,19,9,2,7,15,
     2634        2,6,5,13,25,4,14,13,11,25,1,1,1,2,1,2,2,3,10,11,3,3,1,1,4,4,2,1,4,9,1,4,3,5,5,2,7,12,11,15,7,16,4,5,16,2,1,1,6,3,3,1,1,2,7,6,6,7,1,4,7,6,1,1,
     2635        2,1,12,3,3,9,5,8,1,11,1,2,3,18,20,4,1,3,6,1,7,3,5,5,7,2,2,12,3,1,4,2,3,2,3,11,8,7,4,17,1,9,25,1,1,4,2,2,4,1,2,7,1,1,1,3,1,2,6,16,1,2,1,1,3,12,
     2636        20,2,5,20,8,7,6,2,1,1,1,1,6,2,1,2,10,1,1,6,1,3,1,2,1,4,1,12,4,1,3,1,1,1,1,1,10,4,7,5,13,1,15,1,1,30,11,9,1,15,38,14,1,32,17,20,1,9,31,2,21,9,
     2637        4,49,22,2,1,13,1,11,45,35,43,55,12,19,83,1,3,2,3,13,2,1,7,3,18,3,13,8,1,8,18,5,3,7,25,24,9,24,40,3,17,24,2,1,6,2,3,16,15,6,7,3,12,1,9,7,3,3,
     2638        3,15,21,5,16,4,5,12,11,11,3,6,3,2,31,3,2,1,1,23,6,6,1,4,2,6,5,2,1,1,3,3,22,2,6,2,3,17,3,2,4,5,1,9,5,1,1,6,15,12,3,17,2,14,2,8,1,23,16,4,2,23,
     2639        8,15,23,20,12,25,19,47,11,21,65,46,4,3,1,5,6,1,2,5,26,2,1,1,3,11,1,1,1,2,1,2,3,1,1,10,2,3,1,1,1,3,6,3,2,2,6,6,9,2,2,2,6,2,5,10,2,4,1,2,1,2,2,
     2640        3,1,1,3,1,2,9,23,9,2,1,1,1,1,5,3,2,1,10,9,6,1,10,2,31,25,3,7,5,40,1,15,6,17,7,27,180,1,3,2,2,1,1,1,6,3,10,7,1,3,6,17,8,6,2,2,1,3,5,5,8,16,14,
     2641        15,1,1,4,1,2,1,1,1,3,2,7,5,6,2,5,10,1,4,2,9,1,1,11,6,1,44,1,3,7,9,5,1,3,1,1,10,7,1,10,4,2,7,21,15,7,2,5,1,8,3,4,1,3,1,6,1,4,2,1,4,10,8,1,4,5,
     2642        1,5,10,2,7,1,10,1,1,3,4,11,10,29,4,7,3,5,2,3,33,5,2,19,3,1,4,2,6,31,11,1,3,3,3,1,8,10,9,12,11,12,8,3,14,8,6,11,1,4,41,3,1,2,7,13,1,5,6,2,6,12,
     2643        12,22,5,9,4,8,9,9,34,6,24,1,1,20,9,9,3,4,1,7,2,2,2,6,2,28,5,3,6,1,4,6,7,4,2,1,4,2,13,6,4,4,3,1,8,8,3,2,1,5,1,2,2,3,1,11,11,7,3,6,10,8,6,16,16,
     2644        22,7,12,6,21,5,4,6,6,3,6,1,3,2,1,2,8,29,1,10,1,6,13,6,6,19,31,1,13,4,4,22,17,26,33,10,4,15,12,25,6,67,10,2,3,1,6,10,2,6,2,9,1,9,4,4,1,2,16,2,
     2645        5,9,2,3,8,1,8,3,9,4,8,6,4,8,11,3,2,1,1,3,26,1,7,5,1,11,1,5,3,5,2,13,6,39,5,1,5,2,11,6,10,5,1,15,5,3,6,19,21,22,2,4,1,6,1,8,1,4,8,2,4,2,2,9,2,
     2646        1,1,1,4,3,6,3,12,7,1,14,2,4,10,2,13,1,17,7,3,2,1,3,2,13,7,14,12,3,1,29,2,8,9,15,14,9,14,1,3,1,6,5,9,11,3,38,43,20,7,7,8,5,15,12,19,15,81,8,7,
     2647        1,5,73,13,37,28,8,8,1,15,18,20,165,28,1,6,11,8,4,14,7,15,1,3,3,6,4,1,7,14,1,1,11,30,1,5,1,4,14,1,4,2,7,52,2,6,29,3,1,9,1,21,3,5,1,26,3,11,14,
     2648        11,1,17,5,1,2,1,3,2,8,1,2,9,12,1,1,2,3,8,3,24,12,7,7,5,17,3,3,3,1,23,10,4,4,6,3,1,16,17,22,3,10,21,16,16,6,4,10,2,1,1,2,8,8,6,5,3,3,3,39,25,
     2649        15,1,1,16,6,7,25,15,6,6,12,1,22,13,1,4,9,5,12,2,9,1,12,28,8,3,5,10,22,60,1,2,40,4,61,63,4,1,13,12,1,4,31,12,1,14,89,5,16,6,29,14,2,5,49,18,18,
     2650        5,29,33,47,1,17,1,19,12,2,9,7,39,12,3,7,12,39,3,1,46,4,12,3,8,9,5,31,15,18,3,2,2,66,19,13,17,5,3,46,124,13,57,34,2,5,4,5,8,1,1,1,4,3,1,17,5,
     2651        3,5,3,1,8,5,6,3,27,3,26,7,12,7,2,17,3,7,18,78,16,4,36,1,2,1,6,2,1,39,17,7,4,13,4,4,4,1,10,4,2,4,6,3,10,1,19,1,26,2,4,33,2,73,47,7,3,8,2,4,15,
     2652        18,1,29,2,41,14,1,21,16,41,7,39,25,13,44,2,2,10,1,13,7,1,7,3,5,20,4,8,2,49,1,10,6,1,6,7,10,7,11,16,3,12,20,4,10,3,1,2,11,2,28,9,2,4,7,2,15,1,
     2653        27,1,28,17,4,5,10,7,3,24,10,11,6,26,3,2,7,2,2,49,16,10,16,15,4,5,27,61,30,14,38,22,2,7,5,1,3,12,23,24,17,17,3,3,2,4,1,6,2,7,5,1,1,5,1,1,9,4,
     2654        1,3,6,1,8,2,8,4,14,3,5,11,4,1,3,32,1,19,4,1,13,11,5,2,1,8,6,8,1,6,5,13,3,23,11,5,3,16,3,9,10,1,24,3,198,52,4,2,2,5,14,5,4,22,5,20,4,11,6,41,
     2655        1,5,2,2,11,5,2,28,35,8,22,3,18,3,10,7,5,3,4,1,5,3,8,9,3,6,2,16,22,4,5,5,3,3,18,23,2,6,23,5,27,8,1,33,2,12,43,16,5,2,3,6,1,20,4,2,9,7,1,11,2,
     2656        10,3,14,31,9,3,25,18,20,2,5,5,26,14,1,11,17,12,40,19,9,6,31,83,2,7,9,19,78,12,14,21,76,12,113,79,34,4,1,1,61,18,85,10,2,2,13,31,11,50,6,33,159,
     2657        179,6,6,7,4,4,2,4,2,5,8,7,20,32,22,1,3,10,6,7,28,5,10,9,2,77,19,13,2,5,1,4,4,7,4,13,3,9,31,17,3,26,2,6,6,5,4,1,7,11,3,4,2,1,6,2,20,4,1,9,2,6,
     2658        3,7,1,1,1,20,2,3,1,6,2,3,6,2,4,8,1,5,13,8,4,11,23,1,10,6,2,1,3,21,2,2,4,24,31,4,10,10,2,5,192,15,4,16,7,9,51,1,2,1,1,5,1,1,2,1,3,5,3,1,3,4,1,
     2659        3,1,3,3,9,8,1,2,2,2,4,4,18,12,92,2,10,4,3,14,5,25,16,42,4,14,4,2,21,5,126,30,31,2,1,5,13,3,22,5,6,6,20,12,1,14,12,87,3,19,1,8,2,9,9,3,3,23,2,
     2660        3,7,6,3,1,2,3,9,1,3,1,6,3,2,1,3,11,3,1,6,10,3,2,3,1,2,1,5,1,1,11,3,6,4,1,7,2,1,2,5,5,34,4,14,18,4,19,7,5,8,2,6,79,1,5,2,14,8,2,9,2,1,36,28,16,
     2661        4,1,1,1,2,12,6,42,39,16,23,7,15,15,3,2,12,7,21,64,6,9,28,8,12,3,3,41,59,24,51,55,57,294,9,9,2,6,2,15,1,2,13,38,90,9,9,9,3,11,7,1,1,1,5,6,3,2,
     2662        1,2,2,3,8,1,4,4,1,5,7,1,4,3,20,4,9,1,1,1,5,5,17,1,5,2,6,2,4,1,4,5,7,3,18,11,11,32,7,5,4,7,11,127,8,4,3,3,1,10,1,1,6,21,14,1,16,1,7,1,3,6,9,65,
     2663        51,4,3,13,3,10,1,1,12,9,21,110,3,19,24,1,1,10,62,4,1,29,42,78,28,20,18,82,6,3,15,6,84,58,253,15,155,264,15,21,9,14,7,58,40,39,
     2664    };
     2665    static ImWchar base_ranges[] = // not zero-terminated
     2666    {
     2667        0x0020, 0x00FF, // Basic Latin + Latin Supplement
     2668        0x3000, 0x30FF, // CJK Symbols and Punctuations, Hiragana, Katakana
     2669        0x31F0, 0x31FF, // Katakana Phonetic Extensions
     2670        0xFF00, 0xFFEF  // Half-width characters
     2671    };
     2672    static ImWchar full_ranges[IM_ARRAYSIZE(base_ranges) + IM_ARRAYSIZE(accumulative_offsets_from_0x4E00)*2 + 1] = { 0 };
     2673    if (!full_ranges[0])
     2674    {
     2675        memcpy(full_ranges, base_ranges, sizeof(base_ranges));
     2676        UnpackAccumulativeOffsetsIntoRanges(0x4E00, accumulative_offsets_from_0x4E00, IM_ARRAYSIZE(accumulative_offsets_from_0x4E00), full_ranges + IM_ARRAYSIZE(base_ranges));
     2677    }
     2678    return &full_ranges[0];
    20812679}
    20822680
    20832681const ImWchar*  ImFontAtlas::GetGlyphRangesCyrillic()
    20842682{
    2085    static const ImWchar ranges[] =
    2086    {
    2087       0x0020, 0x00FF, // Basic Latin + Latin Supplement
    2088       0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
    2089       0x2DE0, 0x2DFF, // Cyrillic Extended-A
    2090       0xA640, 0xA69F, // Cyrillic Extended-B
    2091       0,
    2092    };
    2093    return &ranges[0];
     2683    static const ImWchar ranges[] =
     2684    {
     2685        0x0020, 0x00FF, // Basic Latin + Latin Supplement
     2686        0x0400, 0x052F, // Cyrillic + Cyrillic Supplement
     2687        0x2DE0, 0x2DFF, // Cyrillic Extended-A
     2688        0xA640, 0xA69F, // Cyrillic Extended-B
     2689        0,
     2690    };
     2691    return &ranges[0];
    20942692}
    20952693
    20962694const ImWchar*  ImFontAtlas::GetGlyphRangesThai()
    20972695{
    2098    static const ImWchar ranges[] =
    2099    {
    2100       0x0020, 0x00FF, // Basic Latin
    2101       0x2010, 0x205E, // Punctuations
    2102       0x0E00, 0x0E7F, // Thai
    2103       0,
    2104    };
    2105    return &ranges[0];
     2696    static const ImWchar ranges[] =
     2697    {
     2698        0x0020, 0x00FF, // Basic Latin
     2699        0x2010, 0x205E, // Punctuations
     2700        0x0E00, 0x0E7F, // Thai
     2701        0,
     2702    };
     2703    return &ranges[0];
     2704}
     2705
     2706const ImWchar*  ImFontAtlas::GetGlyphRangesVietnamese()
     2707{
     2708    static const ImWchar ranges[] =
     2709    {
     2710        0x0020, 0x00FF, // Basic Latin
     2711        0x0102, 0x0103,
     2712        0x0110, 0x0111,
     2713        0x0128, 0x0129,
     2714        0x0168, 0x0169,
     2715        0x01A0, 0x01A1,
     2716        0x01AF, 0x01B0,
     2717        0x1EA0, 0x1EF9,
     2718        0,
     2719    };
     2720    return &ranges[0];
    21062721}
    21072722
    21082723//-----------------------------------------------------------------------------
    2109 // ImFontAtlas::GlyphRangesBuilder
     2724// [SECTION] ImFontGlyphRangesBuilder
    21102725//-----------------------------------------------------------------------------
    21112726
    2112 void ImFontAtlas::GlyphRangesBuilder::AddText(const char* text, const char* text_end)
    2113 {
    2114    while (text_end ? (text < text_end) : *text)
    2115    {
    2116       unsigned int c = 0;
    2117       int c_len = ImTextCharFromUtf8(&c, text, text_end);
    2118       text += c_len;
    2119       if (c_len == 0)
    2120          break;
    2121       if (c < 0x10000)
    2122          AddChar((ImWchar)c);
    2123    }
    2124 }
    2125 
    2126 void ImFontAtlas::GlyphRangesBuilder::AddRanges(const ImWchar* ranges)
    2127 {
    2128    for (; ranges[0]; ranges += 2)
    2129       for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
    2130          AddChar(c);
    2131 }
    2132 
    2133 void ImFontAtlas::GlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
    2134 {
    2135    for (int n = 0; n < 0x10000; n++)
    2136       if (GetBit(n))
    2137       {
    2138          out_ranges->push_back((ImWchar)n);
    2139          while (n < 0x10000 && GetBit(n + 1))
    2140             n++;
    2141          out_ranges->push_back((ImWchar)n);
    2142       }
    2143    out_ranges->push_back(0);
     2727void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
     2728{
     2729    while (text_end ? (text < text_end) : *text)
     2730    {
     2731        unsigned int c = 0;
     2732        int c_len = ImTextCharFromUtf8(&c, text, text_end);
     2733        text += c_len;
     2734        if (c_len == 0)
     2735            break;
     2736        AddChar((ImWchar)c);
     2737    }
     2738}
     2739
     2740void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
     2741{
     2742    for (; ranges[0]; ranges += 2)
     2743        for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
     2744            AddChar(c);
     2745}
     2746
     2747void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
     2748{
     2749    const int max_codepoint = IM_UNICODE_CODEPOINT_MAX;
     2750    for (int n = 0; n <= max_codepoint; n++)
     2751        if (GetBit(n))
     2752        {
     2753            out_ranges->push_back((ImWchar)n);
     2754            while (n < max_codepoint && GetBit(n + 1))
     2755                n++;
     2756            out_ranges->push_back((ImWchar)n);
     2757        }
     2758    out_ranges->push_back(0);
    21442759}
    21452760
    21462761//-----------------------------------------------------------------------------
    2147 // ImFont
     2762// [SECTION] ImFont
    21482763//-----------------------------------------------------------------------------
    21492764
    21502765ImFont::ImFont()
    21512766{
    2152    Scale = 1.0f;
    2153    FallbackChar = (ImWchar)'?';
    2154    DisplayOffset = ImVec2(0.0f, 0.0f);
    2155    ClearOutputData();
     2767    FontSize = 0.0f;
     2768    FallbackAdvanceX = 0.0f;
     2769    FallbackChar = (ImWchar)'?';
     2770    EllipsisChar = (ImWchar)-1;
     2771    FallbackGlyph = NULL;
     2772    ContainerAtlas = NULL;
     2773    ConfigData = NULL;
     2774    ConfigDataCount = 0;
     2775    DirtyLookupTables = false;
     2776    Scale = 1.0f;
     2777    Ascent = Descent = 0.0f;
     2778    MetricsTotalSurface = 0;
     2779    memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
    21562780}
    21572781
    21582782ImFont::~ImFont()
    21592783{
    2160    // Invalidate active font so that the user gets a clear crash instead of a dangling pointer.
    2161    // If you want to delete fonts you need to do it between Render() and NewFrame().
    2162    // FIXME-CLEANUP
    2163    /*
    2164    ImGuiContext& g = *GImGui;
    2165    if (g.Font == this)
    2166    g.Font = NULL;
    2167    */
    2168    ClearOutputData();
     2784    ClearOutputData();
    21692785}
    21702786
    21712787void    ImFont::ClearOutputData()
    21722788{
    2173    FontSize = 0.0f;
    2174    Glyphs.clear();
    2175    IndexAdvanceX.clear();
    2176    IndexLookup.clear();
    2177    FallbackGlyph = NULL;
    2178    FallbackAdvanceX = 0.0f;
    2179    ConfigDataCount = 0;
    2180    ConfigData = NULL;
    2181    ContainerAtlas = NULL;
    2182    Ascent = Descent = 0.0f;
    2183    DirtyLookupTables = true;
    2184    MetricsTotalSurface = 0;
     2789    FontSize = 0.0f;
     2790    FallbackAdvanceX = 0.0f;
     2791    Glyphs.clear();
     2792    IndexAdvanceX.clear();
     2793    IndexLookup.clear();
     2794    FallbackGlyph = NULL;
     2795    ContainerAtlas = NULL;
     2796    DirtyLookupTables = true;
     2797    Ascent = Descent = 0.0f;
     2798    MetricsTotalSurface = 0;
    21852799}
    21862800
    21872801void ImFont::BuildLookupTable()
    21882802{
    2189    int max_codepoint = 0;
    2190    for (int i = 0; i != Glyphs.Size; i++)
    2191       max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
    2192 
    2193    IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
    2194    IndexAdvanceX.clear();
    2195    IndexLookup.clear();
    2196    DirtyLookupTables = false;
    2197    GrowIndex(max_codepoint + 1);
    2198    for (int i = 0; i < Glyphs.Size; i++)
    2199    {
    2200       int codepoint = (int)Glyphs[i].Codepoint;
    2201       IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
    2202       IndexLookup[codepoint] = (unsigned short)i;
    2203    }
    2204 
    2205    // Create a glyph to handle TAB
    2206    // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
    2207    if (FindGlyph((unsigned short)' '))
    2208    {
    2209       if (Glyphs.back().Codepoint != '\t')   // So we can call this function multiple times
    2210          Glyphs.resize(Glyphs.Size + 1);
    2211       ImFontGlyph& tab_glyph = Glyphs.back();
    2212       tab_glyph = *FindGlyph((unsigned short)' ');
    2213       tab_glyph.Codepoint = '\t';
    2214       tab_glyph.AdvanceX *= 4;
    2215       IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
    2216       IndexLookup[(int)tab_glyph.Codepoint] = (unsigned short)(Glyphs.Size - 1);
    2217    }
    2218 
    2219    FallbackGlyph = FindGlyphNoFallback(FallbackChar);
    2220    FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f;
    2221    for (int i = 0; i < max_codepoint + 1; i++)
    2222       if (IndexAdvanceX[i] < 0.0f)
    2223          IndexAdvanceX[i] = FallbackAdvanceX;
     2803    int max_codepoint = 0;
     2804    for (int i = 0; i != Glyphs.Size; i++)
     2805        max_codepoint = ImMax(max_codepoint, (int)Glyphs[i].Codepoint);
     2806
     2807    // Build lookup table
     2808    IM_ASSERT(Glyphs.Size < 0xFFFF); // -1 is reserved
     2809    IndexAdvanceX.clear();
     2810    IndexLookup.clear();
     2811    DirtyLookupTables = false;
     2812    memset(Used4kPagesMap, 0, sizeof(Used4kPagesMap));
     2813    GrowIndex(max_codepoint + 1);
     2814    for (int i = 0; i < Glyphs.Size; i++)
     2815    {
     2816        int codepoint = (int)Glyphs[i].Codepoint;
     2817        IndexAdvanceX[codepoint] = Glyphs[i].AdvanceX;
     2818        IndexLookup[codepoint] = (ImWchar)i;
     2819
     2820        // Mark 4K page as used
     2821        const int page_n = codepoint / 4096;
     2822        Used4kPagesMap[page_n >> 3] |= 1 << (page_n & 7);
     2823    }
     2824
     2825    // Create a glyph to handle TAB
     2826    // FIXME: Needs proper TAB handling but it needs to be contextualized (or we could arbitrary say that each string starts at "column 0" ?)
     2827    if (FindGlyph((ImWchar)' '))
     2828    {
     2829        if (Glyphs.back().Codepoint != '\t')   // So we can call this function multiple times (FIXME: Flaky)
     2830            Glyphs.resize(Glyphs.Size + 1);
     2831        ImFontGlyph& tab_glyph = Glyphs.back();
     2832        tab_glyph = *FindGlyph((ImWchar)' ');
     2833        tab_glyph.Codepoint = '\t';
     2834        tab_glyph.AdvanceX *= IM_TABSIZE;
     2835        IndexAdvanceX[(int)tab_glyph.Codepoint] = (float)tab_glyph.AdvanceX;
     2836        IndexLookup[(int)tab_glyph.Codepoint] = (ImWchar)(Glyphs.Size - 1);
     2837    }
     2838
     2839    // Mark special glyphs as not visible (note that AddGlyph already mark as non-visible glyphs with zero-size polygons)
     2840    SetGlyphVisible((ImWchar)' ', false);
     2841    SetGlyphVisible((ImWchar)'\t', false);
     2842
     2843    // Setup fall-backs
     2844    FallbackGlyph = FindGlyphNoFallback(FallbackChar);
     2845    FallbackAdvanceX = FallbackGlyph ? FallbackGlyph->AdvanceX : 0.0f;
     2846    for (int i = 0; i < max_codepoint + 1; i++)
     2847        if (IndexAdvanceX[i] < 0.0f)
     2848            IndexAdvanceX[i] = FallbackAdvanceX;
     2849}
     2850
     2851// API is designed this way to avoid exposing the 4K page size
     2852// e.g. use with IsGlyphRangeUnused(0, 255)
     2853bool ImFont::IsGlyphRangeUnused(unsigned int c_begin, unsigned int c_last)
     2854{
     2855    unsigned int page_begin = (c_begin / 4096);
     2856    unsigned int page_last = (c_last / 4096);
     2857    for (unsigned int page_n = page_begin; page_n <= page_last; page_n++)
     2858        if ((page_n >> 3) < sizeof(Used4kPagesMap))
     2859            if (Used4kPagesMap[page_n >> 3] & (1 << (page_n & 7)))
     2860                return false;
     2861    return true;
     2862}
     2863
     2864void ImFont::SetGlyphVisible(ImWchar c, bool visible)
     2865{
     2866    if (ImFontGlyph* glyph = (ImFontGlyph*)(void*)FindGlyph((ImWchar)c))
     2867        glyph->Visible = visible ? 1 : 0;
    22242868}
    22252869
    22262870void ImFont::SetFallbackChar(ImWchar c)
    22272871{
    2228    FallbackChar = c;
    2229    BuildLookupTable();
     2872    FallbackChar = c;
     2873    BuildLookupTable();
    22302874}
    22312875
    22322876void ImFont::GrowIndex(int new_size)
    22332877{
    2234    IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
    2235    if (new_size <= IndexLookup.Size)
    2236       return;
    2237    IndexAdvanceX.resize(new_size, -1.0f);
    2238    IndexLookup.resize(new_size, (unsigned short)-1);
    2239 }
    2240 
    2241 void ImFont::AddGlyph(ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
    2242 {
    2243    Glyphs.resize(Glyphs.Size + 1);
    2244    ImFontGlyph& glyph = Glyphs.back();
    2245    glyph.Codepoint = (ImWchar)codepoint;
    2246    glyph.X0 = x0;
    2247    glyph.Y0 = y0;
    2248    glyph.X1 = x1;
    2249    glyph.Y1 = y1;
    2250    glyph.U0 = u0;
    2251    glyph.V0 = v0;
    2252    glyph.U1 = u1;
    2253    glyph.V1 = v1;
    2254    glyph.AdvanceX = advance_x + ConfigData->GlyphExtraSpacing.x;  // Bake spacing into AdvanceX
    2255 
    2256    if (ConfigData->PixelSnapH)
    2257       glyph.AdvanceX = (float)(int)(glyph.AdvanceX + 0.5f);
    2258 
    2259    // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
    2260    DirtyLookupTables = true;
    2261    MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + 1.99f) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + 1.99f);
     2878    IM_ASSERT(IndexAdvanceX.Size == IndexLookup.Size);
     2879    if (new_size <= IndexLookup.Size)
     2880        return;
     2881    IndexAdvanceX.resize(new_size, -1.0f);
     2882    IndexLookup.resize(new_size, (ImWchar)-1);
     2883}
     2884
     2885// x0/y0/x1/y1 are offset from the character upper-left layout position, in pixels. Therefore x0/y0 are often fairly close to zero.
     2886// Not to be mistaken with texture coordinates, which are held by u0/v0/u1/v1 in normalized format (0.0..1.0 on each texture axis).
     2887// 'cfg' is not necessarily == 'this->ConfigData' because multiple source fonts+configs can be used to build one target font.
     2888void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, float y0, float x1, float y1, float u0, float v0, float u1, float v1, float advance_x)
     2889{
     2890    if (cfg != NULL)
     2891    {
     2892        // Clamp & recenter if needed
     2893        const float advance_x_original = advance_x;
     2894        advance_x = ImClamp(advance_x, cfg->GlyphMinAdvanceX, cfg->GlyphMaxAdvanceX);
     2895        if (advance_x != advance_x_original)
     2896        {
     2897            float char_off_x = cfg->PixelSnapH ? ImFloor((advance_x - advance_x_original) * 0.5f) : (advance_x - advance_x_original) * 0.5f;
     2898            x0 += char_off_x;
     2899            x1 += char_off_x;
     2900        }
     2901
     2902        // Snap to pixel
     2903        if (cfg->PixelSnapH)
     2904            advance_x = IM_ROUND(advance_x);
     2905
     2906        // Bake spacing
     2907        advance_x += cfg->GlyphExtraSpacing.x;
     2908    }
     2909
     2910    Glyphs.resize(Glyphs.Size + 1);
     2911    ImFontGlyph& glyph = Glyphs.back();
     2912    glyph.Codepoint = (unsigned int)codepoint;
     2913    glyph.Visible = (x0 != x1) && (y0 != y1);
     2914    glyph.X0 = x0;
     2915    glyph.Y0 = y0;
     2916    glyph.X1 = x1;
     2917    glyph.Y1 = y1;
     2918    glyph.U0 = u0;
     2919    glyph.V0 = v0;
     2920    glyph.U1 = u1;
     2921    glyph.V1 = v1;
     2922    glyph.AdvanceX = advance_x;
     2923
     2924    // Compute rough surface usage metrics (+1 to account for average padding, +0.99 to round)
     2925    // We use (U1-U0)*TexWidth instead of X1-X0 to account for oversampling.
     2926    float pad = ContainerAtlas->TexGlyphPadding + 0.99f;
     2927    DirtyLookupTables = true;
     2928    MetricsTotalSurface += (int)((glyph.U1 - glyph.U0) * ContainerAtlas->TexWidth + pad) * (int)((glyph.V1 - glyph.V0) * ContainerAtlas->TexHeight + pad);
    22622929}
    22632930
    22642931void ImFont::AddRemapChar(ImWchar dst, ImWchar src, bool overwrite_dst)
    22652932{
    2266    IM_ASSERT(IndexLookup.Size > 0);    // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
    2267    int index_size = IndexLookup.Size;
    2268 
    2269    if (dst < index_size && IndexLookup.Data[dst] == (unsigned short)-1 && !overwrite_dst) // 'dst' already exists
    2270       return;
    2271    if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
    2272       return;
    2273 
    2274    GrowIndex(dst + 1);
    2275    IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (unsigned short)-1;
    2276    IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
     2933    IM_ASSERT(IndexLookup.Size > 0);    // Currently this can only be called AFTER the font has been built, aka after calling ImFontAtlas::GetTexDataAs*() function.
     2934    unsigned int index_size = (unsigned int)IndexLookup.Size;
     2935
     2936    if (dst < index_size && IndexLookup.Data[dst] == (ImWchar)-1 && !overwrite_dst) // 'dst' already exists
     2937        return;
     2938    if (src >= index_size && dst >= index_size) // both 'dst' and 'src' don't exist -> no-op
     2939        return;
     2940
     2941    GrowIndex(dst + 1);
     2942    IndexLookup[dst] = (src < index_size) ? IndexLookup.Data[src] : (ImWchar)-1;
     2943    IndexAdvanceX[dst] = (src < index_size) ? IndexAdvanceX.Data[src] : 1.0f;
    22772944}
    22782945
    22792946const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
    22802947{
    2281    if (c >= IndexLookup.Size)
    2282       return FallbackGlyph;
    2283    const unsigned short i = IndexLookup[c];
    2284    if (i == (unsigned short)-1)
    2285       return FallbackGlyph;
    2286    return &Glyphs.Data[i];
     2948    if (c >= (size_t)IndexLookup.Size)
     2949        return FallbackGlyph;
     2950    const ImWchar i = IndexLookup.Data[c];
     2951    if (i == (ImWchar)-1)
     2952        return FallbackGlyph;
     2953    return &Glyphs.Data[i];
    22872954}
    22882955
    22892956const ImFontGlyph* ImFont::FindGlyphNoFallback(ImWchar c) const
    22902957{
    2291    if (c >= IndexLookup.Size)
    2292       return NULL;
    2293    const unsigned short i = IndexLookup[c];
    2294    if (i == (unsigned short)-1)
    2295       return NULL;
    2296    return &Glyphs.Data[i];
     2958    if (c >= (size_t)IndexLookup.Size)
     2959        return NULL;
     2960    const ImWchar i = IndexLookup.Data[c];
     2961    if (i == (ImWchar)-1)
     2962        return NULL;
     2963    return &Glyphs.Data[i];
    22972964}
    22982965
    22992966const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const char* text_end, float wrap_width) const
    23002967{
    2301    // Simple word-wrapping for English, not full-featured. Please submit failing cases!
    2302    // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
    2303 
    2304    // For references, possible wrap point marked with ^
    2305    //  "aaa bbb, ccc,ddd. eee   fff. ggg!"
    2306    //      ^    ^    ^   ^   ^__    ^    ^
    2307 
    2308    // List of hardcoded separators: .,;!?'"
    2309 
    2310    // Skip extra blanks after a line returns (that includes not counting them in width computation)
    2311    // e.g. "Hello    world" --> "Hello" "World"
    2312 
    2313    // Cut words that cannot possibly fit within one line.
    2314    // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
    2315 
    2316    float line_width = 0.0f;
    2317    float word_width = 0.0f;
    2318    float blank_width = 0.0f;
    2319    wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
    2320 
    2321    const char* word_end = text;
    2322    const char* prev_word_end = NULL;
    2323    bool inside_word = true;
    2324 
    2325    const char* s = text;
    2326    while (s < text_end)
    2327    {
    2328       unsigned int c = (unsigned int)*s;
    2329       const char* next_s;
    2330       if (c < 0x80)
    2331          next_s = s + 1;
    2332       else
    2333          next_s = s + ImTextCharFromUtf8(&c, s, text_end);
    2334       if (c == 0)
    2335          break;
    2336 
    2337       if (c < 32)
    2338       {
    2339          if (c == '\n')
    2340          {
    2341             line_width = word_width = blank_width = 0.0f;
    2342             inside_word = true;
    2343             s = next_s;
     2968    // Simple word-wrapping for English, not full-featured. Please submit failing cases!
     2969    // FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
     2970
     2971    // For references, possible wrap point marked with ^
     2972    //  "aaa bbb, ccc,ddd. eee   fff. ggg!"
     2973    //      ^    ^    ^   ^   ^__    ^    ^
     2974
     2975    // List of hardcoded separators: .,;!?'"
     2976
     2977    // Skip extra blanks after a line returns (that includes not counting them in width computation)
     2978    // e.g. "Hello    world" --> "Hello" "World"
     2979
     2980    // Cut words that cannot possibly fit within one line.
     2981    // e.g.: "The tropical fish" with ~5 characters worth of width --> "The tr" "opical" "fish"
     2982
     2983    float line_width = 0.0f;
     2984    float word_width = 0.0f;
     2985    float blank_width = 0.0f;
     2986    wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
     2987
     2988    const char* word_end = text;
     2989    const char* prev_word_end = NULL;
     2990    bool inside_word = true;
     2991
     2992    const char* s = text;
     2993    while (s < text_end)
     2994    {
     2995        unsigned int c = (unsigned int)*s;
     2996        const char* next_s;
     2997        if (c < 0x80)
     2998            next_s = s + 1;
     2999        else
     3000            next_s = s + ImTextCharFromUtf8(&c, s, text_end);
     3001        if (c == 0)
     3002            break;
     3003
     3004        if (c < 32)
     3005        {
     3006            if (c == '\n')
     3007            {
     3008                line_width = word_width = blank_width = 0.0f;
     3009                inside_word = true;
     3010                s = next_s;
     3011                continue;
     3012            }
     3013            if (c == '\r')
     3014            {
     3015                s = next_s;
     3016                continue;
     3017            }
     3018        }
     3019
     3020        const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX);
     3021        if (ImCharIsBlankW(c))
     3022        {
     3023            if (inside_word)
     3024            {
     3025                line_width += blank_width;
     3026                blank_width = 0.0f;
     3027                word_end = s;
     3028            }
     3029            blank_width += char_width;
     3030            inside_word = false;
     3031        }
     3032        else
     3033        {
     3034            word_width += char_width;
     3035            if (inside_word)
     3036            {
     3037                word_end = next_s;
     3038            }
     3039            else
     3040            {
     3041                prev_word_end = word_end;
     3042                line_width += word_width + blank_width;
     3043                word_width = blank_width = 0.0f;
     3044            }
     3045
     3046            // Allow wrapping after punctuation.
     3047            inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"');
     3048        }
     3049
     3050        // We ignore blank width at the end of the line (they can be skipped)
     3051        if (line_width + word_width > wrap_width)
     3052        {
     3053            // Words that cannot possibly fit within an entire line will be cut anywhere.
     3054            if (word_width < wrap_width)
     3055                s = prev_word_end ? prev_word_end : word_end;
     3056            break;
     3057        }
     3058
     3059        s = next_s;
     3060    }
     3061
     3062    return s;
     3063}
     3064
     3065ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const
     3066{
     3067    if (!text_end)
     3068        text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
     3069
     3070    const float line_height = size;
     3071    const float scale = size / FontSize;
     3072
     3073    ImVec2 text_size = ImVec2(0, 0);
     3074    float line_width = 0.0f;
     3075
     3076    const bool word_wrap_enabled = (wrap_width > 0.0f);
     3077    const char* word_wrap_eol = NULL;
     3078
     3079    const char* s = text_begin;
     3080    while (s < text_end)
     3081    {
     3082        if (word_wrap_enabled)
     3083        {
     3084            // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
     3085            if (!word_wrap_eol)
     3086            {
     3087                word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width);
     3088                if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
     3089                    word_wrap_eol++;    // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
     3090            }
     3091
     3092            if (s >= word_wrap_eol)
     3093            {
     3094                if (text_size.x < line_width)
     3095                    text_size.x = line_width;
     3096                text_size.y += line_height;
     3097                line_width = 0.0f;
     3098                word_wrap_eol = NULL;
     3099
     3100                // Wrapping skips upcoming blanks
     3101                while (s < text_end)
     3102                {
     3103                    const char c = *s;
     3104                    if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
     3105                }
     3106                continue;
     3107            }
     3108        }
     3109
     3110        // Decode and advance source
     3111        const char* prev_s = s;
     3112        unsigned int c = (unsigned int)*s;
     3113        if (c < 0x80)
     3114        {
     3115            s += 1;
     3116        }
     3117        else
     3118        {
     3119            s += ImTextCharFromUtf8(&c, s, text_end);
     3120            if (c == 0) // Malformed UTF-8?
     3121                break;
     3122        }
     3123
     3124        if (c < 32)
     3125        {
     3126            if (c == '\n')
     3127            {
     3128                text_size.x = ImMax(text_size.x, line_width);
     3129                text_size.y += line_height;
     3130                line_width = 0.0f;
     3131                continue;
     3132            }
     3133            if (c == '\r')
     3134                continue;
     3135        }
     3136
     3137        const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX.Data[c] : FallbackAdvanceX) * scale;
     3138        if (line_width + char_width >= max_width)
     3139        {
     3140            s = prev_s;
     3141            break;
     3142        }
     3143
     3144        line_width += char_width;
     3145    }
     3146
     3147    if (text_size.x < line_width)
     3148        text_size.x = line_width;
     3149
     3150    if (line_width > 0 || text_size.y == 0.0f)
     3151        text_size.y += line_height;
     3152
     3153    if (remaining)
     3154        *remaining = s;
     3155
     3156    return text_size;
     3157}
     3158
     3159void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, ImWchar c) const
     3160{
     3161    const ImFontGlyph* glyph = FindGlyph(c);
     3162    if (!glyph || !glyph->Visible)
     3163        return;
     3164    float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
     3165    pos.x = IM_FLOOR(pos.x);
     3166    pos.y = IM_FLOOR(pos.y);
     3167    draw_list->PrimReserve(6, 4);
     3168    draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
     3169}
     3170
     3171void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
     3172{
     3173    if (!text_end)
     3174        text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
     3175
     3176    // Align to be pixel perfect
     3177    pos.x = IM_FLOOR(pos.x);
     3178    pos.y = IM_FLOOR(pos.y);
     3179    float x = pos.x;
     3180    float y = pos.y;
     3181    if (y > clip_rect.w)
     3182        return;
     3183
     3184    const float scale = size / FontSize;
     3185    const float line_height = FontSize * scale;
     3186    const bool word_wrap_enabled = (wrap_width > 0.0f);
     3187    const char* word_wrap_eol = NULL;
     3188
     3189    // Fast-forward to first visible line
     3190    const char* s = text_begin;
     3191    if (y + line_height < clip_rect.y && !word_wrap_enabled)
     3192        while (y + line_height < clip_rect.y && s < text_end)
     3193        {
     3194            s = (const char*)memchr(s, '\n', text_end - s);
     3195            s = s ? s + 1 : text_end;
     3196            y += line_height;
     3197        }
     3198
     3199    // For large text, scan for the last visible line in order to avoid over-reserving in the call to PrimReserve()
     3200    // Note that very large horizontal line will still be affected by the issue (e.g. a one megabyte string buffer without a newline will likely crash atm)
     3201    if (text_end - s > 10000 && !word_wrap_enabled)
     3202    {
     3203        const char* s_end = s;
     3204        float y_end = y;
     3205        while (y_end < clip_rect.w && s_end < text_end)
     3206        {
     3207            s_end = (const char*)memchr(s_end, '\n', text_end - s_end);
     3208            s_end = s_end ? s_end + 1 : text_end;
     3209            y_end += line_height;
     3210        }
     3211        text_end = s_end;
     3212    }
     3213    if (s == text_end)
     3214        return;
     3215
     3216    // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
     3217    const int vtx_count_max = (int)(text_end - s) * 4;
     3218    const int idx_count_max = (int)(text_end - s) * 6;
     3219    const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
     3220    draw_list->PrimReserve(idx_count_max, vtx_count_max);
     3221
     3222    ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
     3223    ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
     3224    unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
     3225
     3226    while (s < text_end)
     3227    {
     3228        if (word_wrap_enabled)
     3229        {
     3230            // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
     3231            if (!word_wrap_eol)
     3232            {
     3233                word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
     3234                if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
     3235                    word_wrap_eol++;    // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
     3236            }
     3237
     3238            if (s >= word_wrap_eol)
     3239            {
     3240                x = pos.x;
     3241                y += line_height;
     3242                word_wrap_eol = NULL;
     3243
     3244                // Wrapping skips upcoming blanks
     3245                while (s < text_end)
     3246                {
     3247                    const char c = *s;
     3248                    if (ImCharIsBlankA(c)) { s++; } else if (c == '\n') { s++; break; } else { break; }
     3249                }
     3250                continue;
     3251            }
     3252        }
     3253
     3254        // Decode and advance source
     3255        unsigned int c = (unsigned int)*s;
     3256        if (c < 0x80)
     3257        {
     3258            s += 1;
     3259        }
     3260        else
     3261        {
     3262            s += ImTextCharFromUtf8(&c, s, text_end);
     3263            if (c == 0) // Malformed UTF-8?
     3264                break;
     3265        }
     3266
     3267        if (c < 32)
     3268        {
     3269            if (c == '\n')
     3270            {
     3271                x = pos.x;
     3272                y += line_height;
     3273                if (y > clip_rect.w)
     3274                    break; // break out of main loop
     3275                continue;
     3276            }
     3277            if (c == '\r')
     3278                continue;
     3279        }
     3280
     3281        const ImFontGlyph* glyph = FindGlyph((ImWchar)c);
     3282        if (glyph == NULL)
    23443283            continue;
    2345          }
    2346          if (c == '\r')
    2347          {
    2348             s = next_s;
    2349             continue;
    2350          }
    2351       }
    2352 
    2353       const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX);
    2354       if (ImCharIsSpace(c))
    2355       {
    2356          if (inside_word)
    2357          {
    2358             line_width += blank_width;
    2359             blank_width = 0.0f;
    2360             word_end = s;
    2361          }
    2362          blank_width += char_width;
    2363          inside_word = false;
    2364       }
    2365       else
    2366       {
    2367          word_width += char_width;
    2368          if (inside_word)
    2369          {
    2370             word_end = next_s;
    2371          }
    2372          else
    2373          {
    2374             prev_word_end = word_end;
    2375             line_width += word_width + blank_width;
    2376             word_width = blank_width = 0.0f;
    2377          }
    2378 
    2379          // Allow wrapping after punctuation.
    2380          inside_word = !(c == '.' || c == ',' || c == ';' || c == '!' || c == '?' || c == '\"');
    2381       }
    2382 
    2383       // We ignore blank width at the end of the line (they can be skipped)
    2384       if (line_width + word_width >= wrap_width)
    2385       {
    2386          // Words that cannot possibly fit within an entire line will be cut anywhere.
    2387          if (word_width < wrap_width)
    2388             s = prev_word_end ? prev_word_end : word_end;
    2389          break;
    2390       }
    2391 
    2392       s = next_s;
    2393    }
    2394 
    2395    return s;
    2396 }
    2397 
    2398 ImVec2 ImFont::CalcTextSizeA(float size, float max_width, float wrap_width, const char* text_begin, const char* text_end, const char** remaining) const
    2399 {
    2400    if (!text_end)
    2401       text_end = text_begin + strlen(text_begin); // FIXME-OPT: Need to avoid this.
    2402 
    2403    const float line_height = size;
    2404    const float scale = size / FontSize;
    2405 
    2406    ImVec2 text_size = ImVec2(0, 0);
    2407    float line_width = 0.0f;
    2408 
    2409    const bool word_wrap_enabled = (wrap_width > 0.0f);
    2410    const char* word_wrap_eol = NULL;
    2411 
    2412    const char* s = text_begin;
    2413    while (s < text_end)
    2414    {
    2415       if (word_wrap_enabled)
    2416       {
    2417          // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
    2418          if (!word_wrap_eol)
    2419          {
    2420             word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - line_width);
    2421             if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
    2422                word_wrap_eol++;    // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
    2423          }
    2424 
    2425          if (s >= word_wrap_eol)
    2426          {
    2427             if (text_size.x < line_width)
    2428                text_size.x = line_width;
    2429             text_size.y += line_height;
    2430             line_width = 0.0f;
    2431             word_wrap_eol = NULL;
    2432 
    2433             // Wrapping skips upcoming blanks
    2434             while (s < text_end)
    2435             {
    2436                const char c = *s;
    2437                if (ImCharIsSpace((unsigned int)c)) { s++; }
    2438                else if (c == '\n') { s++; break; }
    2439                else { break; }
    2440             }
    2441             continue;
    2442          }
    2443       }
    2444 
    2445       // Decode and advance source
    2446       const char* prev_s = s;
    2447       unsigned int c = (unsigned int)*s;
    2448       if (c < 0x80)
    2449       {
    2450          s += 1;
    2451       }
    2452       else
    2453       {
    2454          s += ImTextCharFromUtf8(&c, s, text_end);
    2455          if (c == 0) // Malformed UTF-8?
    2456             break;
    2457       }
    2458 
    2459       if (c < 32)
    2460       {
    2461          if (c == '\n')
    2462          {
    2463             text_size.x = ImMax(text_size.x, line_width);
    2464             text_size.y += line_height;
    2465             line_width = 0.0f;
    2466             continue;
    2467          }
    2468          if (c == '\r')
    2469             continue;
    2470       }
    2471 
    2472       const float char_width = ((int)c < IndexAdvanceX.Size ? IndexAdvanceX[(int)c] : FallbackAdvanceX) * scale;
    2473       if (line_width + char_width >= max_width)
    2474       {
    2475          s = prev_s;
    2476          break;
    2477       }
    2478 
    2479       line_width += char_width;
    2480    }
    2481 
    2482    if (text_size.x < line_width)
    2483       text_size.x = line_width;
    2484 
    2485    if (line_width > 0 || text_size.y == 0.0f)
    2486       text_size.y += line_height;
    2487 
    2488    if (remaining)
    2489       *remaining = s;
    2490 
    2491    return text_size;
    2492 }
    2493 
    2494 void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, unsigned short c) const
    2495 {
    2496    if (c == ' ' || c == '\t' || c == '\n' || c == '\r') // Match behavior of RenderText(), those 4 codepoints are hard-coded.
    2497       return;
    2498    if (const ImFontGlyph* glyph = FindGlyph(c))
    2499    {
    2500       float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f;
    2501       pos.x = (float)(int)pos.x + DisplayOffset.x;
    2502       pos.y = (float)(int)pos.y + DisplayOffset.y;
    2503       draw_list->PrimReserve(6, 4);
    2504       draw_list->PrimRectUV(ImVec2(pos.x + glyph->X0 * scale, pos.y + glyph->Y0 * scale), ImVec2(pos.x + glyph->X1 * scale, pos.y + glyph->Y1 * scale), ImVec2(glyph->U0, glyph->V0), ImVec2(glyph->U1, glyph->V1), col);
    2505    }
    2506 }
    2507 
    2508 void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
    2509 {
    2510    if (!text_end)
    2511       text_end = text_begin + strlen(text_begin); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls.
    2512 
    2513                                                   // Align to be pixel perfect
    2514    pos.x = (float)(int)pos.x + DisplayOffset.x;
    2515    pos.y = (float)(int)pos.y + DisplayOffset.y;
    2516    float x = pos.x;
    2517    float y = pos.y;
    2518    if (y > clip_rect.w)
    2519       return;
    2520 
    2521    const float scale = size / FontSize;
    2522    const float line_height = FontSize * scale;
    2523    const bool word_wrap_enabled = (wrap_width > 0.0f);
    2524    const char* word_wrap_eol = NULL;
    2525 
    2526    // Skip non-visible lines
    2527    const char* s = text_begin;
    2528    if (!word_wrap_enabled && y + line_height < clip_rect.y)
    2529       while (s < text_end && *s != '\n')  // Fast-forward to next line
    2530          s++;
    2531 
    2532    // Reserve vertices for remaining worse case (over-reserving is useful and easily amortized)
    2533    const int vtx_count_max = (int)(text_end - s) * 4;
    2534    const int idx_count_max = (int)(text_end - s) * 6;
    2535    const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
    2536    draw_list->PrimReserve(idx_count_max, vtx_count_max);
    2537 
    2538    ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
    2539    ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
    2540    unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
    2541 
    2542    while (s < text_end)
    2543    {
    2544       if (word_wrap_enabled)
    2545       {
    2546          // Calculate how far we can render. Requires two passes on the string data but keeps the code simple and not intrusive for what's essentially an uncommon feature.
    2547          if (!word_wrap_eol)
    2548          {
    2549             word_wrap_eol = CalcWordWrapPositionA(scale, s, text_end, wrap_width - (x - pos.x));
    2550             if (word_wrap_eol == s) // Wrap_width is too small to fit anything. Force displaying 1 character to minimize the height discontinuity.
    2551                word_wrap_eol++;    // +1 may not be a character start point in UTF-8 but it's ok because we use s >= word_wrap_eol below
    2552          }
    2553 
    2554          if (s >= word_wrap_eol)
    2555          {
    2556             x = pos.x;
    2557             y += line_height;
    2558             word_wrap_eol = NULL;
    2559 
    2560             // Wrapping skips upcoming blanks
    2561             while (s < text_end)
    2562             {
    2563                const char c = *s;
    2564                if (ImCharIsSpace((unsigned int)c)) { s++; }
    2565                else if (c == '\n') { s++; break; }
    2566                else { break; }
    2567             }
    2568             continue;
    2569          }
    2570       }
    2571 
    2572       // Decode and advance source
    2573       unsigned int c = (unsigned int)*s;
    2574       if (c < 0x80)
    2575       {
    2576          s += 1;
    2577       }
    2578       else
    2579       {
    2580          s += ImTextCharFromUtf8(&c, s, text_end);
    2581          if (c == 0) // Malformed UTF-8?
    2582             break;
    2583       }
    2584 
    2585       if (c < 32)
    2586       {
    2587          if (c == '\n')
    2588          {
    2589             x = pos.x;
    2590             y += line_height;
    2591 
    2592             if (y > clip_rect.w)
    2593                break;
    2594             if (!word_wrap_enabled && y + line_height < clip_rect.y)
    2595                while (s < text_end && *s != '\n')  // Fast-forward to next line
    2596                   s++;
    2597             continue;
    2598          }
    2599          if (c == '\r')
    2600             continue;
    2601       }
    2602 
    2603       float char_width = 0.0f;
    2604       if (const ImFontGlyph* glyph = FindGlyph((unsigned short)c))
    2605       {
    2606          char_width = glyph->AdvanceX * scale;
    2607 
    2608          // Arbitrarily assume that both space and tabs are empty glyphs as an optimization
    2609          if (c != ' ' && c != '\t')
    2610          {
     3284
     3285        float char_width = glyph->AdvanceX * scale;
     3286        if (glyph->Visible)
     3287        {
    26113288            // We don't do a second finer clipping test on the Y axis as we've already skipped anything before clip_rect.y and exit once we pass clip_rect.w
    26123289            float x1 = x + glyph->X0 * scale;
     
    26163293            if (x1 <= clip_rect.z && x2 >= clip_rect.x)
    26173294            {
    2618                // Render a character
    2619                float u1 = glyph->U0;
    2620                float v1 = glyph->V0;
    2621                float u2 = glyph->U1;
    2622                float v2 = glyph->V1;
    2623 
    2624                // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
    2625                if (cpu_fine_clip)
    2626                {
    2627                   if (x1 < clip_rect.x)
    2628                   {
    2629                      u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
    2630                      x1 = clip_rect.x;
    2631                   }
    2632                   if (y1 < clip_rect.y)
    2633                   {
    2634                      v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
    2635                      y1 = clip_rect.y;
    2636                   }
    2637                   if (x2 > clip_rect.z)
    2638                   {
    2639                      u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
    2640                      x2 = clip_rect.z;
    2641                   }
    2642                   if (y2 > clip_rect.w)
    2643                   {
    2644                      v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
    2645                      y2 = clip_rect.w;
    2646                   }
    2647                   if (y1 >= y2)
    2648                   {
    2649                      x += char_width;
    2650                      continue;
    2651                   }
    2652                }
    2653 
    2654                // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
    2655                {
    2656                   idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx + 1); idx_write[2] = (ImDrawIdx)(vtx_current_idx + 2);
    2657                   idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx + 2); idx_write[5] = (ImDrawIdx)(vtx_current_idx + 3);
    2658                   vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
    2659                   vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
    2660                   vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
    2661                   vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
    2662                   vtx_write += 4;
    2663                   vtx_current_idx += 4;
    2664                   idx_write += 6;
    2665                }
     3295                // Render a character
     3296                float u1 = glyph->U0;
     3297                float v1 = glyph->V0;
     3298                float u2 = glyph->U1;
     3299                float v2 = glyph->V1;
     3300
     3301                // CPU side clipping used to fit text in their frame when the frame is too small. Only does clipping for axis aligned quads.
     3302                if (cpu_fine_clip)
     3303                {
     3304                    if (x1 < clip_rect.x)
     3305                    {
     3306                        u1 = u1 + (1.0f - (x2 - clip_rect.x) / (x2 - x1)) * (u2 - u1);
     3307                        x1 = clip_rect.x;
     3308                    }
     3309                    if (y1 < clip_rect.y)
     3310                    {
     3311                        v1 = v1 + (1.0f - (y2 - clip_rect.y) / (y2 - y1)) * (v2 - v1);
     3312                        y1 = clip_rect.y;
     3313                    }
     3314                    if (x2 > clip_rect.z)
     3315                    {
     3316                        u2 = u1 + ((clip_rect.z - x1) / (x2 - x1)) * (u2 - u1);
     3317                        x2 = clip_rect.z;
     3318                    }
     3319                    if (y2 > clip_rect.w)
     3320                    {
     3321                        v2 = v1 + ((clip_rect.w - y1) / (y2 - y1)) * (v2 - v1);
     3322                        y2 = clip_rect.w;
     3323                    }
     3324                    if (y1 >= y2)
     3325                    {
     3326                        x += char_width;
     3327                        continue;
     3328                    }
     3329                }
     3330
     3331                // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
     3332                {
     3333                    idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2);
     3334                    idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3);
     3335                    vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
     3336                    vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
     3337                    vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
     3338                    vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
     3339                    vtx_write += 4;
     3340                    vtx_current_idx += 4;
     3341                    idx_write += 6;
     3342                }
    26663343            }
    2667          }
    2668       }
    2669 
    2670       x += char_width;
    2671    }
    2672 
    2673    // Give back unused vertices
    2674    draw_list->VtxBuffer.resize((int)(vtx_write - draw_list->VtxBuffer.Data));
    2675    draw_list->IdxBuffer.resize((int)(idx_write - draw_list->IdxBuffer.Data));
    2676    draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
    2677    draw_list->_VtxWritePtr = vtx_write;
    2678    draw_list->_IdxWritePtr = idx_write;
    2679    draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size;
     3344        }
     3345        x += char_width;
     3346    }
     3347
     3348    // Give back unused vertices (clipped ones, blanks) ~ this is essentially a PrimUnreserve() action.
     3349    draw_list->VtxBuffer.Size = (int)(vtx_write - draw_list->VtxBuffer.Data); // Same as calling shrink()
     3350    draw_list->IdxBuffer.Size = (int)(idx_write - draw_list->IdxBuffer.Data);
     3351    draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
     3352    draw_list->_VtxWritePtr = vtx_write;
     3353    draw_list->_IdxWritePtr = idx_write;
     3354    draw_list->_VtxCurrentIdx = vtx_current_idx;
    26803355}
    26813356
    26823357//-----------------------------------------------------------------------------
    2683 // Internals Drawing Helpers
     3358// [SECTION] ImGui Internal Render Helpers
    26843359//-----------------------------------------------------------------------------
     3360// Vaguely redesigned to stop accessing ImGui global state:
     3361// - RenderArrow()
     3362// - RenderBullet()
     3363// - RenderCheckMark()
     3364// - RenderMouseCursor()
     3365// - RenderArrowPointingAt()
     3366// - RenderRectFilledRangeH()
     3367//-----------------------------------------------------------------------------
     3368// Function in need of a redesign (legacy mess)
     3369// - RenderColorRectWithAlphaCheckerboard()
     3370//-----------------------------------------------------------------------------
     3371
     3372// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state
     3373void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale)
     3374{
     3375    const float h = draw_list->_Data->FontSize * 1.00f;
     3376    float r = h * 0.40f * scale;
     3377    ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale);
     3378
     3379    ImVec2 a, b, c;
     3380    switch (dir)
     3381    {
     3382    case ImGuiDir_Up:
     3383    case ImGuiDir_Down:
     3384        if (dir == ImGuiDir_Up) r = -r;
     3385        a = ImVec2(+0.000f, +0.750f) * r;
     3386        b = ImVec2(-0.866f, -0.750f) * r;
     3387        c = ImVec2(+0.866f, -0.750f) * r;
     3388        break;
     3389    case ImGuiDir_Left:
     3390    case ImGuiDir_Right:
     3391        if (dir == ImGuiDir_Left) r = -r;
     3392        a = ImVec2(+0.750f, +0.000f) * r;
     3393        b = ImVec2(-0.750f, +0.866f) * r;
     3394        c = ImVec2(-0.750f, -0.866f) * r;
     3395        break;
     3396    case ImGuiDir_None:
     3397    case ImGuiDir_COUNT:
     3398        IM_ASSERT(0);
     3399        break;
     3400    }
     3401    draw_list->AddTriangleFilled(center + a, center + b, center + c, col);
     3402}
     3403
     3404void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
     3405{
     3406    draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);
     3407}
     3408
     3409void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz)
     3410{
     3411    float thickness = ImMax(sz / 5.0f, 1.0f);
     3412    sz -= thickness * 0.5f;
     3413    pos += ImVec2(thickness * 0.25f, thickness * 0.25f);
     3414
     3415    float third = sz / 3.0f;
     3416    float bx = pos.x + third;
     3417    float by = pos.y + sz - third * 0.5f;
     3418    draw_list->PathLineTo(ImVec2(bx - third, by - third));
     3419    draw_list->PathLineTo(ImVec2(bx, by));
     3420    draw_list->PathLineTo(ImVec2(bx + third * 2.0f, by - third * 2.0f));
     3421    draw_list->PathStroke(col, false, thickness);
     3422}
     3423
     3424void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
     3425{
     3426    if (mouse_cursor == ImGuiMouseCursor_None)
     3427        return;
     3428    IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
     3429
     3430    ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas;
     3431    ImVec2 offset, size, uv[4];
     3432    if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
     3433    {
     3434        pos -= offset;
     3435        const ImTextureID tex_id = font_atlas->TexID;
     3436        draw_list->PushTextureID(tex_id);
     3437        draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale,    uv[2], uv[3], col_shadow);
     3438        draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale,    uv[2], uv[3], col_shadow);
     3439        draw_list->AddImage(tex_id, pos,                        pos + size * scale,                     uv[2], uv[3], col_border);
     3440        draw_list->AddImage(tex_id, pos,                        pos + size * scale,                     uv[0], uv[1], col_fill);
     3441        draw_list->PopTextureID();
     3442    }
     3443}
     3444
     3445// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
     3446void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
     3447{
     3448    switch (direction)
     3449    {
     3450    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;
     3451    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;
     3452    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;
     3453    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;
     3454    case ImGuiDir_None: case ImGuiDir_COUNT: break; // Fix warnings
     3455    }
     3456}
    26853457
    26863458static inline float ImAcos01(float x)
    26873459{
    2688    if (x <= 0.0f) return IM_PI * 0.5f;
    2689    if (x >= 1.0f) return 0.0f;
    2690    return acosf(x);
    2691    //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.
     3460    if (x <= 0.0f) return IM_PI * 0.5f;
     3461    if (x >= 1.0f) return 0.0f;
     3462    return ImAcos(x);
     3463    //return (-0.69813170079773212f * x * x - 0.87266462599716477f) * x + 1.5707963267948966f; // Cheap approximation, may be enough for what we do.
    26923464}
    26933465
     
    26953467void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
    26963468{
    2697    if (x_end_norm == x_start_norm)
    2698       return;
    2699    if (x_start_norm > x_end_norm)
    2700       ImSwap(x_start_norm, x_end_norm);
    2701 
    2702    ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);
    2703    ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);
    2704    if (rounding == 0.0f)
    2705    {
    2706       draw_list->AddRectFilled(p0, p1, col, 0.0f);
    2707       return;
    2708    }
    2709 
    2710    rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding);
    2711    const float inv_rounding = 1.0f / rounding;
    2712    const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
    2713    const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
    2714    const float x0 = ImMax(p0.x, rect.Min.x + rounding);
    2715    if (arc0_b == arc0_e)
    2716    {
    2717       draw_list->PathLineTo(ImVec2(x0, p1.y));
    2718       draw_list->PathLineTo(ImVec2(x0, p0.y));
    2719    }
    2720    else if (arc0_b == 0.0f && arc0_e == IM_PI * 0.5f)
    2721    {
    2722       draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
    2723       draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
    2724    }
    2725    else
    2726    {
    2727       draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL
    2728       draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR
    2729    }
    2730    if (p1.x > rect.Min.x + rounding)
    2731    {
    2732       const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);
    2733       const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);
    2734       const float x1 = ImMin(p1.x, rect.Max.x - rounding);
    2735       if (arc1_b == arc1_e)
    2736       {
    2737          draw_list->PathLineTo(ImVec2(x1, p0.y));
    2738          draw_list->PathLineTo(ImVec2(x1, p1.y));
    2739       }
    2740       else if (arc1_b == 0.0f && arc1_e == IM_PI * 0.5f)
    2741       {
    2742          draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
    2743          draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3);  // BR
    2744       }
    2745       else
    2746       {
    2747          draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR
    2748          draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR
    2749       }
    2750    }
    2751    draw_list->PathFillConvex(col);
     3469    if (x_end_norm == x_start_norm)
     3470        return;
     3471    if (x_start_norm > x_end_norm)
     3472        ImSwap(x_start_norm, x_end_norm);
     3473
     3474    ImVec2 p0 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_start_norm), rect.Min.y);
     3475    ImVec2 p1 = ImVec2(ImLerp(rect.Min.x, rect.Max.x, x_end_norm), rect.Max.y);
     3476    if (rounding == 0.0f)
     3477    {
     3478        draw_list->AddRectFilled(p0, p1, col, 0.0f);
     3479        return;
     3480    }
     3481
     3482    rounding = ImClamp(ImMin((rect.Max.x - rect.Min.x) * 0.5f, (rect.Max.y - rect.Min.y) * 0.5f) - 1.0f, 0.0f, rounding);
     3483    const float inv_rounding = 1.0f / rounding;
     3484    const float arc0_b = ImAcos01(1.0f - (p0.x - rect.Min.x) * inv_rounding);
     3485    const float arc0_e = ImAcos01(1.0f - (p1.x - rect.Min.x) * inv_rounding);
     3486    const float half_pi = IM_PI * 0.5f; // We will == compare to this because we know this is the exact value ImAcos01 can return.
     3487    const float x0 = ImMax(p0.x, rect.Min.x + rounding);
     3488    if (arc0_b == arc0_e)
     3489    {
     3490        draw_list->PathLineTo(ImVec2(x0, p1.y));
     3491        draw_list->PathLineTo(ImVec2(x0, p0.y));
     3492    }
     3493    else if (arc0_b == 0.0f && arc0_e == half_pi)
     3494    {
     3495        draw_list->PathArcToFast(ImVec2(x0, p1.y - rounding), rounding, 3, 6); // BL
     3496        draw_list->PathArcToFast(ImVec2(x0, p0.y + rounding), rounding, 6, 9); // TR
     3497    }
     3498    else
     3499    {
     3500        draw_list->PathArcTo(ImVec2(x0, p1.y - rounding), rounding, IM_PI - arc0_e, IM_PI - arc0_b, 3); // BL
     3501        draw_list->PathArcTo(ImVec2(x0, p0.y + rounding), rounding, IM_PI + arc0_b, IM_PI + arc0_e, 3); // TR
     3502    }
     3503    if (p1.x > rect.Min.x + rounding)
     3504    {
     3505        const float arc1_b = ImAcos01(1.0f - (rect.Max.x - p1.x) * inv_rounding);
     3506        const float arc1_e = ImAcos01(1.0f - (rect.Max.x - p0.x) * inv_rounding);
     3507        const float x1 = ImMin(p1.x, rect.Max.x - rounding);
     3508        if (arc1_b == arc1_e)
     3509        {
     3510            draw_list->PathLineTo(ImVec2(x1, p0.y));
     3511            draw_list->PathLineTo(ImVec2(x1, p1.y));
     3512        }
     3513        else if (arc1_b == 0.0f && arc1_e == half_pi)
     3514        {
     3515            draw_list->PathArcToFast(ImVec2(x1, p0.y + rounding), rounding, 9, 12); // TR
     3516            draw_list->PathArcToFast(ImVec2(x1, p1.y - rounding), rounding, 0, 3);  // BR
     3517        }
     3518        else
     3519        {
     3520            draw_list->PathArcTo(ImVec2(x1, p0.y + rounding), rounding, -arc1_e, -arc1_b, 3); // TR
     3521            draw_list->PathArcTo(ImVec2(x1, p1.y - rounding), rounding, +arc1_b, +arc1_e, 3); // BR
     3522        }
     3523    }
     3524    draw_list->PathFillConvex(col);
     3525}
     3526
     3527void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding)
     3528{
     3529    const bool fill_L = (inner.Min.x > outer.Min.x);
     3530    const bool fill_R = (inner.Max.x < outer.Max.x);
     3531    const bool fill_U = (inner.Min.y > outer.Min.y);
     3532    const bool fill_D = (inner.Max.y < outer.Max.y);
     3533    if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopLeft) | (fill_D ? 0 : ImDrawCornerFlags_BotLeft));
     3534    if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopRight) | (fill_D ? 0 : ImDrawCornerFlags_BotRight));
     3535    if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_TopLeft) | (fill_R ? 0 : ImDrawCornerFlags_TopRight));
     3536    if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_BotLeft) | (fill_R ? 0 : ImDrawCornerFlags_BotRight));
     3537    if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopLeft);
     3538    if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopRight);
     3539    if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotLeft);
     3540    if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight);
     3541}
     3542
     3543// Helper for ColorPicker4()
     3544// 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.
     3545// 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 altogether.
     3546// FIXME: uses ImGui::GetColorU32
     3547void ImGui::RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags)
     3548{
     3549    if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
     3550    {
     3551        ImU32 col_bg1 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(204, 204, 204, 255), col));
     3552        ImU32 col_bg2 = ImGui::GetColorU32(ImAlphaBlendColors(IM_COL32(128, 128, 128, 255), col));
     3553        draw_list->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags);
     3554
     3555        int yi = 0;
     3556        for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)
     3557        {
     3558            float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
     3559            if (y2 <= y1)
     3560                continue;
     3561            for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
     3562            {
     3563                float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
     3564                if (x2 <= x1)
     3565                    continue;
     3566                int rounding_corners_flags_cell = 0;
     3567                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; }
     3568                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; }
     3569                rounding_corners_flags_cell &= rounding_corners_flags;
     3570                draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell);
     3571            }
     3572        }
     3573    }
     3574    else
     3575    {
     3576        draw_list->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags);
     3577    }
    27523578}
    27533579
    27543580//-----------------------------------------------------------------------------
    2755 // DEFAULT FONT DATA
     3581// [SECTION] Decompression code
    27563582//-----------------------------------------------------------------------------
    2757 // Compressed with stb_compress() then converted to a C array.
     3583// Compressed with stb_compress() then converted to a C array and encoded as base85.
    27583584// Use the program in misc/fonts/binary_to_compressed_c.cpp to create the array from a TTF file.
     3585// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
    27593586// Decompression from stb.h (public domain) by Sean Barrett https://github.com/nothings/stb/blob/master/stb.h
    27603587//-----------------------------------------------------------------------------
     
    27623589static unsigned int stb_decompress_length(const unsigned char *input)
    27633590{
    2764    return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
     3591    return (input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11];
    27653592}
    27663593
     
    27703597static void stb__match(const unsigned char *data, unsigned int length)
    27713598{
    2772    // INVERSE of memmove... write each byte before copying the next...
    2773    IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
    2774    if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
    2775    if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e + 1; return; }
    2776    while (length--) *stb__dout++ = *data++;
     3599    // INVERSE of memmove... write each byte before copying the next...
     3600    IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
     3601    if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
     3602    if (data < stb__barrier_out_b) { stb__dout = stb__barrier_out_e+1; return; }
     3603    while (length--) *stb__dout++ = *data++;
    27773604}
    27783605
    27793606static void stb__lit(const unsigned char *data, unsigned int length)
    27803607{
    2781    IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
    2782    if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
    2783    if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e + 1; return; }
    2784    memcpy(stb__dout, data, length);
    2785    stb__dout += length;
     3608    IM_ASSERT(stb__dout + length <= stb__barrier_out_e);
     3609    if (stb__dout + length > stb__barrier_out_e) { stb__dout += length; return; }
     3610    if (data < stb__barrier_in_b) { stb__dout = stb__barrier_out_e+1; return; }
     3611    memcpy(stb__dout, data, length);
     3612    stb__dout += length;
    27863613}
    27873614
     
    27923619static const unsigned char *stb_decompress_token(const unsigned char *i)
    27933620{
    2794    if (*i >= 0x20) { // use fewer if's for cases that expand small
    2795       if (*i >= 0x80)       stb__match(stb__dout - i[1] - 1, i[0] - 0x80 + 1), i += 2;
    2796       else if (*i >= 0x40)  stb__match(stb__dout - (stb__in2(0) - 0x4000 + 1), i[2] + 1), i += 3;
    2797       else /* *i >= 0x20 */ stb__lit(i + 1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
    2798    }
    2799    else { // more ifs for cases that expand large, since overhead is amortized
    2800       if (*i >= 0x18)       stb__match(stb__dout - (stb__in3(0) - 0x180000 + 1), i[3] + 1), i += 4;
    2801       else if (*i >= 0x10)  stb__match(stb__dout - (stb__in3(0) - 0x100000 + 1), stb__in2(3) + 1), i += 5;
    2802       else if (*i >= 0x08)  stb__lit(i + 2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);
    2803       else if (*i == 0x07)  stb__lit(i + 3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);
    2804       else if (*i == 0x06)  stb__match(stb__dout - (stb__in3(1) + 1), i[4] + 1), i += 5;
    2805       else if (*i == 0x04)  stb__match(stb__dout - (stb__in3(1) + 1), stb__in2(4) + 1), i += 6;
    2806    }
    2807    return i;
     3621    if (*i >= 0x20) { // use fewer if's for cases that expand small
     3622        if (*i >= 0x80)       stb__match(stb__dout-i[1]-1, i[0] - 0x80 + 1), i += 2;
     3623        else if (*i >= 0x40)  stb__match(stb__dout-(stb__in2(0) - 0x4000 + 1), i[2]+1), i += 3;
     3624        else /* *i >= 0x20 */ stb__lit(i+1, i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);
     3625    } else { // more ifs for cases that expand large, since overhead is amortized
     3626        if (*i >= 0x18)       stb__match(stb__dout-(stb__in3(0) - 0x180000 + 1), i[3]+1), i += 4;
     3627        else if (*i >= 0x10)  stb__match(stb__dout-(stb__in3(0) - 0x100000 + 1), stb__in2(3)+1), i += 5;
     3628        else if (*i >= 0x08)  stb__lit(i+2, stb__in2(0) - 0x0800 + 1), i += 2 + (stb__in2(0) - 0x0800 + 1);
     3629        else if (*i == 0x07)  stb__lit(i+3, stb__in2(1) + 1), i += 3 + (stb__in2(1) + 1);
     3630        else if (*i == 0x06)  stb__match(stb__dout-(stb__in3(1)+1), i[4]+1), i += 5;
     3631        else if (*i == 0x04)  stb__match(stb__dout-(stb__in3(1)+1), stb__in2(4)+1), i += 6;
     3632    }
     3633    return i;
    28083634}
    28093635
    28103636static unsigned int stb_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)
    28113637{
    2812    const unsigned long ADLER_MOD = 65521;
    2813    unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
    2814    unsigned long blocklen, i;
    2815 
    2816    blocklen = buflen % 5552;
    2817    while (buflen) {
    2818       for (i = 0; i + 7 < blocklen; i += 8) {
    2819          s1 += buffer[0], s2 += s1;
    2820          s1 += buffer[1], s2 += s1;
    2821          s1 += buffer[2], s2 += s1;
    2822          s1 += buffer[3], s2 += s1;
    2823          s1 += buffer[4], s2 += s1;
    2824          s1 += buffer[5], s2 += s1;
    2825          s1 += buffer[6], s2 += s1;
    2826          s1 += buffer[7], s2 += s1;
    2827 
    2828          buffer += 8;
    2829       }
    2830 
    2831       for (; i < blocklen; ++i)
    2832          s1 += *buffer++, s2 += s1;
    2833 
    2834       s1 %= ADLER_MOD, s2 %= ADLER_MOD;
    2835       buflen -= blocklen;
    2836       blocklen = 5552;
    2837    }
    2838    return (unsigned int)(s2 << 16) + (unsigned int)s1;
     3638    const unsigned long ADLER_MOD = 65521;
     3639    unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;
     3640    unsigned long blocklen = buflen % 5552;
     3641
     3642    unsigned long i;
     3643    while (buflen) {
     3644        for (i=0; i + 7 < blocklen; i += 8) {
     3645            s1 += buffer[0], s2 += s1;
     3646            s1 += buffer[1], s2 += s1;
     3647            s1 += buffer[2], s2 += s1;
     3648            s1 += buffer[3], s2 += s1;
     3649            s1 += buffer[4], s2 += s1;
     3650            s1 += buffer[5], s2 += s1;
     3651            s1 += buffer[6], s2 += s1;
     3652            s1 += buffer[7], s2 += s1;
     3653
     3654            buffer += 8;
     3655        }
     3656
     3657        for (; i < blocklen; ++i)
     3658            s1 += *buffer++, s2 += s1;
     3659
     3660        s1 %= ADLER_MOD, s2 %= ADLER_MOD;
     3661        buflen -= blocklen;
     3662        blocklen = 5552;
     3663    }
     3664    return (unsigned int)(s2 << 16) + (unsigned int)s1;
    28393665}
    28403666
    28413667static unsigned int stb_decompress(unsigned char *output, const unsigned char *i, unsigned int /*length*/)
    28423668{
    2843    unsigned int olen;
    2844    if (stb__in4(0) != 0x57bC0000) return 0;
    2845    if (stb__in4(4) != 0)          return 0; // error! stream is > 4GB
    2846    olen = stb_decompress_length(i);
    2847    stb__barrier_in_b = i;
    2848    stb__barrier_out_e = output + olen;
    2849    stb__barrier_out_b = output;
    2850    i += 16;
    2851 
    2852    stb__dout = output;
    2853    for (;;) {
    2854       const unsigned char *old_i = i;
    2855       i = stb_decompress_token(i);
    2856       if (i == old_i) {
    2857          if (*i == 0x05 && i[1] == 0xfa) {
    2858             IM_ASSERT(stb__dout == output + olen);
    2859             if (stb__dout != output + olen) return 0;
    2860             if (stb_adler32(1, output, olen) != (unsigned int)stb__in4(2))
    2861                return 0;
    2862             return olen;
    2863          }
    2864          else {
    2865             IM_ASSERT(0); /* NOTREACHED */
     3669    if (stb__in4(0) != 0x57bC0000) return 0;
     3670    if (stb__in4(4) != 0)          return 0; // error! stream is > 4GB
     3671    const unsigned int olen = stb_decompress_length(i);
     3672    stb__barrier_in_b = i;
     3673    stb__barrier_out_e = output + olen;
     3674    stb__barrier_out_b = output;
     3675    i += 16;
     3676
     3677    stb__dout = output;
     3678    for (;;) {
     3679        const unsigned char *old_i = i;
     3680        i = stb_decompress_token(i);
     3681        if (i == old_i) {
     3682            if (*i == 0x05 && i[1] == 0xfa) {
     3683                IM_ASSERT(stb__dout == output + olen);
     3684                if (stb__dout != output + olen) return 0;
     3685                if (stb_adler32(1, output, olen) != (unsigned int) stb__in4(2))
     3686                    return 0;
     3687                return olen;
     3688            } else {
     3689                IM_ASSERT(0); /* NOTREACHED */
     3690                return 0;
     3691            }
     3692        }
     3693        IM_ASSERT(stb__dout <= output + olen);
     3694        if (stb__dout > output + olen)
    28663695            return 0;
    2867          }
    2868       }
    2869       IM_ASSERT(stb__dout <= output + olen);
    2870       if (stb__dout > output + olen)
    2871          return 0;
    2872    }
    2873 }
    2874 
     3696    }
     3697}
     3698
     3699//-----------------------------------------------------------------------------
     3700// [SECTION] Default font data (ProggyClean.ttf)
    28753701//-----------------------------------------------------------------------------
    28763702// ProggyClean.ttf
     
    28803706//-----------------------------------------------------------------------------
    28813707// File: 'ProggyClean.ttf' (41208 bytes)
    2882 // Exported using binary_to_compressed_c.cpp
     3708// Exported using misc/fonts/binary_to_compressed_c.cpp (with compression + base85 string encoding).
     3709// The purpose of encoding as base85 instead of "0x00,0x01,..." style is only save on _source code_ size.
    28833710//-----------------------------------------------------------------------------
    28843711static const char proggy_clean_ttf_compressed_data_base85[11980 + 1] =
    2885 "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
    2886 "2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#"
    2887 "`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#[email protected]<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL"
    2888 "i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#[email protected]'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N"
    2889 "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"
    2890 "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"
    2891 "tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX"
    2892 "ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc."
    2893 "x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G"
    2894 "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)"
    2895 "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#"
    2896 "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM"
    2897 "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu"
    2898 "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/"
    2899 "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L"
    2900 "%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#"
    2901 "OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)("
    2902 "h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h"
    2903 "o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"
    2904 "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-"
    2905 "sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-"
    2906 "eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO"
    2907 "M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%"
    2908 "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]"
    2909 "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et"
    2910 "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:"
    2911 "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL("
    2912 "$/V,;(kXZejWO`<[5?\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<[email protected];x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<"
    2913 "nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?"
    2914 "7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;"
    2915 ")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M"
    2916 "D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX("
    2917 "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs"
    2918 "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
    2919 "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-"
    2920 "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;[email protected]$m%#QvQS8U@)2Z+3K:AKM5i"
    2921 "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7"
    2922 ".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@"
    2923 "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*"
    2924 "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u"
    2925 "@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#"
    2926 "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#"
    2927 "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0"
    2928 "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"
    2929 "6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#"
    2930 "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD"
    2931 ":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+"
    2932 "tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*"
    2933 "$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7"
    2934 ":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A"
    2935 "7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7"
    2936 "u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT"
    2937 "LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M"
    2938 ":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>"
    2939 "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%"
    2940 "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;"
    2941 "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:"
    2942 "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%"
    2943 "9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-"
    2944 "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*"
    2945 "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY"
    2946 "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
    2947 "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`"
    2948 "0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/"
    2949 "+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj"
    2950 "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V"
    2951 "?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK"
    2952 "Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa"
    2953 ">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>"
    2954 "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I"
    2955 "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#"
    2956 "Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$"
    2957 "MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)"
    2958 "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo"
    2959 "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P"
    2960 "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO"
    2961 "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#"
    2962 ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>"
    2963 "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#"
    2964 "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"
    2965 "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#"
    2966 "/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#"
    2967 "m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#"
    2968 "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
    2969 "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
    2970 "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
     3712    "7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/"
     3713    "2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#"
     3714    "`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#[email protected]<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL"
     3715    "i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#[email protected]'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N"
     3716    "kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N"
     3717    "*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)"
     3718    "tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX"
     3719    "ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc."
     3720    "x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G"
     3721    "CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)"
     3722    "U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#"
     3723    "'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM"
     3724    "_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu"
     3725    "Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/"
     3726    "/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L"
     3727    "%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#"
     3728    "OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)("
     3729    "h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h"
     3730    "o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO"
     3731    "j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-"
     3732    "sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-"
     3733    "eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO"
     3734    "M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%"
     3735    "LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]"
     3736    "%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et"
     3737    "Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:"
     3738    "a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL("
     3739    "$/V,;(kXZejWO`<[5?\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<[email protected];x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<"
     3740    "nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?"
     3741    "7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;"
     3742    ")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M"
     3743    "D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX("
     3744    "P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs"
     3745    "bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q"
     3746    "h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-"
     3747    "V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;[email protected]$m%#QvQS8U@)2Z+3K:AKM5i"
     3748    "sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7"
     3749    ".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@"
     3750    "$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*"
     3751    "hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u"
     3752    "@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#"
     3753    "w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#"
     3754    "u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0"
     3755    "d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8"
     3756    "6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#"
     3757    "b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD"
     3758    ":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+"
     3759    "tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*"
     3760    "$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7"
     3761    ":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A"
     3762    "7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7"
     3763    "u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT"
     3764    "LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M"
     3765    ":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>"
     3766    "_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%"
     3767    "hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;"
     3768    "^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:"
     3769    "+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%"
     3770    "9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-"
     3771    "CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*"
     3772    "hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY"
     3773    "8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-"
     3774    "S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`"
     3775    "0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/"
     3776    "+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj"
     3777    "M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V"
     3778    "?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK"
     3779    "Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa"
     3780    ">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>"
     3781    "[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I"
     3782    "wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#"
     3783    "Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$"
     3784    "MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)"
     3785    "i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo"
     3786    "1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P"
     3787    "iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO"
     3788    "URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#"
     3789    ";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>"
     3790    "w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#"
     3791    "d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4"
     3792    "A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#"
     3793    "/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#"
     3794    "m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#"
     3795    "TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP"
     3796    "GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp"
     3797    "O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#";
    29713798
    29723799static const char* GetDefaultCompressedFontDataTTFBase85()
    29733800{
    2974    return proggy_clean_ttf_compressed_data_base85;
    2975 }
     3801    return proggy_clean_ttf_compressed_data_base85;
     3802}
     3803
     3804#endif // #ifndef IMGUI_DISABLE
  • IMGUI/imgui_internal.h

    r78c3045 re66fd66  
    1 // dear imgui, v1.61 WIP
    2 // (internals)
     1// dear imgui, v1.79
     2// (internal structures/api)
    33
    44// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
     
    77// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators)
    88
     9/*
     10
     11Index of this file:
     12
     13// [SECTION] Header mess
     14// [SECTION] Forward declarations
     15// [SECTION] Context pointer
     16// [SECTION] STB libraries includes
     17// [SECTION] Macros
     18// [SECTION] Generic helpers
     19// [SECTION] ImDrawList support
     20// [SECTION] Widgets support: flags, enums, data structures
     21// [SECTION] Columns support
     22// [SECTION] Settings support
     23// [SECTION] Multi-select support
     24// [SECTION] Docking support
     25// [SECTION] Viewport support
     26// [SECTION] ImGuiContext (main imgui context)
     27// [SECTION] ImGuiWindowTempData, ImGuiWindow
     28// [SECTION] Tab bar, Tab item support
     29// [SECTION] Table support
     30// [SECTION] Internal API
     31// [SECTION] Test Engine Hooks (imgui_test_engine)
     32
     33*/
     34
    935#pragma once
     36#ifndef IMGUI_DISABLE
     37
     38//-----------------------------------------------------------------------------
     39// [SECTION] Header mess
     40//-----------------------------------------------------------------------------
    1041
    1142#ifndef IMGUI_VERSION
     
    1344#endif
    1445
    15 #include <stdio.h>      // FILE*
     46#include <stdio.h>      // FILE*, sscanf
     47#include <stdlib.h>     // NULL, malloc, free, qsort, atoi, atof
    1648#include <math.h>       // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf
    1749#include <limits.h>     // INT_MIN, INT_MAX
    1850
     51// Visual Studio warnings
    1952#ifdef _MSC_VER
    2053#pragma warning (push)
     
    2255#endif
    2356
    24 #ifdef __clang__
     57// Clang/GCC warnings with -Weverything
     58#if defined(__clang__)
    2559#pragma clang diagnostic push
    26 #pragma clang diagnostic ignored "-Wunused-function"        // for stb_textedit.h
    27 #pragma clang diagnostic ignored "-Wmissing-prototypes"     // for stb_textedit.h
     60#if __has_warning("-Wunknown-warning-option")
     61#pragma clang diagnostic ignored "-Wunknown-warning-option"         // warning: unknown warning group 'xxx'
     62#endif
     63#pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
     64#pragma clang diagnostic ignored "-Wunused-function"                // for stb_textedit.h
     65#pragma clang diagnostic ignored "-Wmissing-prototypes"             // for stb_textedit.h
    2866#pragma clang diagnostic ignored "-Wold-style-cast"
    29 #endif
    30 
    31 //-----------------------------------------------------------------------------
    32 // Forward Declarations
    33 //-----------------------------------------------------------------------------
    34 
    35 struct ImRect;
    36 struct ImGuiColMod;
    37 struct ImGuiStyleMod;
    38 struct ImGuiGroupData;
    39 struct ImGuiMenuColumns;
    40 struct ImGuiDrawContext;
    41 struct ImGuiTextEditState;
    42 struct ImGuiPopupRef;
    43 struct ImGuiWindow;
    44 struct ImGuiWindowSettings;
    45 
    46 typedef int ImGuiLayoutType;        // enum: horizontal or vertical             // enum ImGuiLayoutType_
    47 typedef int ImGuiButtonFlags;       // flags: for ButtonEx(), ButtonBehavior()  // enum ImGuiButtonFlags_
    48 typedef int ImGuiItemFlags;         // flags: for PushItemFlag()                // enum ImGuiItemFlags_
    49 typedef int ImGuiItemStatusFlags;   // flags: storage for DC.LastItemXXX        // enum ImGuiItemStatusFlags_
    50 typedef int ImGuiNavHighlightFlags; // flags: for RenderNavHighlight()          // enum ImGuiNavHighlightFlags_
    51 typedef int ImGuiNavDirSourceFlags; // flags: for GetNavInputAmount2d()         // enum ImGuiNavDirSourceFlags_
    52 typedef int ImGuiSeparatorFlags;    // flags: for Separator() - internal        // enum ImGuiSeparatorFlags_
    53 typedef int ImGuiSliderFlags;       // flags: for SliderBehavior()              // enum ImGuiSliderFlags_
    54 
    55                                     //-------------------------------------------------------------------------
    56                                     // STB libraries
    57                                     //-------------------------------------------------------------------------
    58 
    59 namespace ImGuiStb
     67#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
     68#pragma clang diagnostic ignored "-Wdouble-promotion"
     69#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
     70#elif defined(__GNUC__)
     71#pragma GCC diagnostic push
     72#pragma GCC diagnostic ignored "-Wpragmas"              // warning: unknown option after '#pragma GCC diagnostic' kind
     73#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
     74#endif
     75
     76// Legacy defines
     77#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS            // Renamed in 1.74
     78#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
     79#endif
     80#ifdef IMGUI_DISABLE_MATH_FUNCTIONS                     // Renamed in 1.74
     81#error Use IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
     82#endif
     83
     84//-----------------------------------------------------------------------------
     85// [SECTION] Forward declarations
     86//-----------------------------------------------------------------------------
     87
     88struct ImBitVector;                 // Store 1-bit per value
     89struct ImRect;                      // An axis-aligned rectangle (2 points)
     90struct ImDrawDataBuilder;           // Helper to build a ImDrawData instance
     91struct ImDrawListSharedData;        // Data shared between all ImDrawList instances
     92struct ImGuiColorMod;               // Stacked color modifier, backup of modified data so we can restore it
     93struct ImGuiColumnData;             // Storage data for a single column
     94struct ImGuiColumns;                // Storage data for a columns set
     95struct ImGuiContext;                // Main Dear ImGui context
     96struct ImGuiDataTypeInfo;           // Type information associated to a ImGuiDataType enum
     97struct ImGuiGroupData;              // Stacked storage data for BeginGroup()/EndGroup()
     98struct ImGuiInputTextState;         // Internal state of the currently focused/edited text input box
     99struct ImGuiLastItemDataBackup;     // Backup and restore IsItemHovered() internal data
     100struct ImGuiMenuColumns;            // Simple column measurement, currently used for MenuItem() only
     101struct ImGuiNavMoveResult;          // Result of a gamepad/keyboard directional navigation move query result
     102struct ImGuiNextWindowData;         // Storage for SetNextWindow** functions
     103struct ImGuiNextItemData;           // Storage for SetNextItem** functions
     104struct ImGuiPopupData;              // Storage for current popup stack
     105struct ImGuiSettingsHandler;        // Storage for one type registered in the .ini file
     106struct ImGuiStyleMod;               // Stacked style modifier, backup of modified data so we can restore it
     107struct ImGuiTabBar;                 // Storage for a tab bar
     108struct ImGuiTabItem;                // Storage for a tab item (within a tab bar)
     109struct ImGuiWindow;                 // Storage for one window
     110struct ImGuiWindowTempData;         // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame)
     111struct ImGuiWindowSettings;         // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session)
     112
     113// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
     114typedef int ImGuiLayoutType;            // -> enum ImGuiLayoutType_         // Enum: Horizontal or vertical
     115typedef int ImGuiButtonFlags;           // -> enum ImGuiButtonFlags_        // Flags: for ButtonEx(), ButtonBehavior()
     116typedef int ImGuiColumnsFlags;          // -> enum ImGuiColumnsFlags_       // Flags: BeginColumns()
     117typedef int ImGuiItemFlags;             // -> enum ImGuiItemFlags_          // Flags: for PushItemFlag()
     118typedef int ImGuiItemStatusFlags;       // -> enum ImGuiItemStatusFlags_    // Flags: for DC.LastItemStatusFlags
     119typedef int ImGuiNavHighlightFlags;     // -> enum ImGuiNavHighlightFlags_  // Flags: for RenderNavHighlight()
     120typedef int ImGuiNavDirSourceFlags;     // -> enum ImGuiNavDirSourceFlags_  // Flags: for GetNavInputAmount2d()
     121typedef int ImGuiNavMoveFlags;          // -> enum ImGuiNavMoveFlags_       // Flags: for navigation requests
     122typedef int ImGuiNextItemDataFlags;     // -> enum ImGuiNextItemDataFlags_  // Flags: for SetNextItemXXX() functions
     123typedef int ImGuiNextWindowDataFlags;   // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions
     124typedef int ImGuiSeparatorFlags;        // -> enum ImGuiSeparatorFlags_     // Flags: for SeparatorEx()
     125typedef int ImGuiTextFlags;             // -> enum ImGuiTextFlags_          // Flags: for TextEx()
     126typedef int ImGuiTooltipFlags;          // -> enum ImGuiTooltipFlags_       // Flags: for BeginTooltipEx()
     127
     128//-----------------------------------------------------------------------------
     129// [SECTION] Context pointer
     130// See implementation of this variable in imgui.cpp for comments and details.
     131//-----------------------------------------------------------------------------
     132
     133#ifndef GImGui
     134extern IMGUI_API ImGuiContext* GImGui;  // Current implicit context pointer
     135#endif
     136
     137//-------------------------------------------------------------------------
     138// [SECTION] STB libraries includes
     139//-------------------------------------------------------------------------
     140
     141namespace ImStb
    60142{
    61143
    62144#undef STB_TEXTEDIT_STRING
    63145#undef STB_TEXTEDIT_CHARTYPE
    64 #define STB_TEXTEDIT_STRING             ImGuiTextEditState
     146#define STB_TEXTEDIT_STRING             ImGuiInputTextState
    65147#define STB_TEXTEDIT_CHARTYPE           ImWchar
    66 #define STB_TEXTEDIT_GETWIDTH_NEWLINE   -1.0f
    67 #include "stb_textedit.h"
    68 
    69 } // namespace ImGuiStb
    70 
    71   //-----------------------------------------------------------------------------
    72   // Context
    73   //-----------------------------------------------------------------------------
    74 
    75 #ifndef GImGui
    76 extern IMGUI_API ImGuiContext* GImGui;  // Current implicit ImGui context pointer
    77 #endif
    78 
    79                                         //-----------------------------------------------------------------------------
    80                                         // Helpers
    81                                         //-----------------------------------------------------------------------------
    82 
    83 #define IM_PI           3.14159265358979323846f
     148#define STB_TEXTEDIT_GETWIDTH_NEWLINE   (-1.0f)
     149#define STB_TEXTEDIT_UNDOSTATECOUNT     99
     150#define STB_TEXTEDIT_UNDOCHARCOUNT      999
     151#include "imstb_textedit.h"
     152
     153} // namespace ImStb
     154
     155//-----------------------------------------------------------------------------
     156// [SECTION] Macros
     157//-----------------------------------------------------------------------------
     158
     159// Debug Logging
     160#ifndef IMGUI_DEBUG_LOG
     161#define IMGUI_DEBUG_LOG(_FMT,...)       printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
     162#endif
     163
     164// Debug Logging for selected systems. Remove the '((void)0) //' to enable.
     165//#define IMGUI_DEBUG_LOG_POPUP         IMGUI_DEBUG_LOG // Enable log
     166//#define IMGUI_DEBUG_LOG_NAV           IMGUI_DEBUG_LOG // Enable log
     167#define IMGUI_DEBUG_LOG_POPUP(...)      ((void)0)       // Disable log
     168#define IMGUI_DEBUG_LOG_NAV(...)        ((void)0)       // Disable log
     169
     170// Static Asserts
     171#if (__cplusplus >= 201100)
     172#define IM_STATIC_ASSERT(_COND)         static_assert(_COND, "")
     173#else
     174#define IM_STATIC_ASSERT(_COND)         typedef char static_assertion_##__line__[(_COND)?1:-1]
     175#endif
     176
     177// "Paranoid" Debug Asserts are meant to only be enabled during specific debugging/work, otherwise would slow down the code too much.
     178// We currently don't have many of those so the effect is currently negligible, but onward intent to add more aggressive ones in the code.
     179//#define IMGUI_DEBUG_PARANOID
     180#ifdef IMGUI_DEBUG_PARANOID
     181#define IM_ASSERT_PARANOID(_EXPR)       IM_ASSERT(_EXPR)
     182#else
     183#define IM_ASSERT_PARANOID(_EXPR)
     184#endif
     185
     186// Error handling
     187// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults.
     188#ifndef IM_ASSERT_USER_ERROR
     189#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG)   // Recoverable User Error
     190#endif
     191
     192// Misc Macros
     193#define IM_PI                           3.14159265358979323846f
    84194#ifdef _WIN32
    85 #define IM_NEWLINE      "\r\n"   // Play it nice with Windows users (2018: Notepad _still_ doesn't display files properly when they use Unix-style carriage returns)
     195#define IM_NEWLINE                      "\r\n"   // Play it nice with Windows users (Update: since 2018-05, Notepad finally appears to support Unix-style carriage returns!)
    86196#else
    87 #define IM_NEWLINE      "\n"
    88 #endif
    89 
    90                                         // Helpers: UTF-8 <> wchar
    91 IMGUI_API int           ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end);      // return output UTF-8 bytes count
    92 IMGUI_API int           ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end);          // return input UTF-8 bytes count
    93 IMGUI_API int           ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL);   // return input UTF-8 bytes count
    94 IMGUI_API int           ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end);                            // return number of UTF-8 code-points (NOT bytes count)
    95 IMGUI_API int           ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end);                   // return number of bytes to express string as UTF-8 code-points
    96 
    97                                                                                                                            // Helpers: Misc
    98 IMGUI_API ImU32         ImHash(const void* data, int data_size, ImU32 seed = 0);    // Pass data_size==0 for zero-terminated strings
    99 IMGUI_API void*         ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size = NULL, int padding_bytes = 0);
    100 IMGUI_API FILE*         ImFileOpen(const char* filename, const char* file_open_mode);
    101 static inline bool      ImCharIsSpace(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
    102 static inline bool      ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
    103 static inline int       ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
    104 
    105 // Helpers: Geometry
    106 IMGUI_API ImVec2        ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);
    107 IMGUI_API bool          ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
    108 IMGUI_API ImVec2        ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
    109 IMGUI_API void          ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w);
    110 
    111 // Helpers: String
     197#define IM_NEWLINE                      "\n"
     198#endif
     199#define IM_TABSIZE                      (4)
     200#define IM_F32_TO_INT8_UNBOUND(_VAL)    ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f)))   // Unsaturated, for display purpose
     201#define IM_F32_TO_INT8_SAT(_VAL)        ((int)(ImSaturate(_VAL) * 255.0f + 0.5f))               // Saturated, always output 0..255
     202#define IM_FLOOR(_VAL)                  ((float)(int)(_VAL))                                    // ImFloor() is not inlined in MSVC debug builds
     203#define IM_ROUND(_VAL)                  ((float)(int)((_VAL) + 0.5f))                           //
     204
     205// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall
     206#ifdef _MSC_VER
     207#define IMGUI_CDECL __cdecl
     208#else
     209#define IMGUI_CDECL
     210#endif
     211
     212// Debug Tools
     213// Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item.
     214#ifndef IM_DEBUG_BREAK
     215#if defined(__clang__)
     216#define IM_DEBUG_BREAK()    __builtin_debugtrap()
     217#elif defined (_MSC_VER)
     218#define IM_DEBUG_BREAK()    __debugbreak()
     219#else
     220#define IM_DEBUG_BREAK()    IM_ASSERT(0)    // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger!
     221#endif
     222#endif // #ifndef IM_DEBUG_BREAK
     223
     224//-----------------------------------------------------------------------------
     225// [SECTION] Generic helpers
     226// Note that the ImXXX helpers functions are lower-level than ImGui functions.
     227// ImGui functions or the ImGui context are never called/used from other ImXXX functions.
     228//-----------------------------------------------------------------------------
     229// - Helpers: Hashing
     230// - Helpers: Sorting
     231// - Helpers: Bit manipulation
     232// - Helpers: String, Formatting
     233// - Helpers: UTF-8 <> wchar conversions
     234// - Helpers: ImVec2/ImVec4 operators
     235// - Helpers: Maths
     236// - Helpers: Geometry
     237// - Helper: ImVec1
     238// - Helper: ImVec2ih
     239// - Helper: ImRect
     240// - Helper: ImBitArray
     241// - Helper: ImBitVector
     242// - Helper: ImPool<>
     243// - Helper: ImChunkStream<>
     244//-----------------------------------------------------------------------------
     245
     246// Helpers: Hashing
     247IMGUI_API ImU32         ImHashData(const void* data, size_t data_size, ImU32 seed = 0);
     248IMGUI_API ImU32         ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0);
     249#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     250static inline ImU32     ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68]
     251#endif
     252
     253// Helpers: Sorting
     254#define ImQsort         qsort
     255
     256// Helpers: Color Blending
     257IMGUI_API ImU32         ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);
     258
     259// Helpers: Bit manipulation
     260static inline bool      ImIsPowerOfTwo(int v)           { return v != 0 && (v & (v - 1)) == 0; }
     261static inline int       ImUpperPowerOfTwo(int v)        { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
     262
     263// Helpers: String, Formatting
    112264IMGUI_API int           ImStricmp(const char* str1, const char* str2);
    113265IMGUI_API int           ImStrnicmp(const char* str1, const char* str2, size_t count);
    114266IMGUI_API void          ImStrncpy(char* dst, const char* src, size_t count);
    115267IMGUI_API char*         ImStrdup(const char* str);
     268IMGUI_API char*         ImStrdupcpy(char* dst, size_t* p_dst_size, const char* str);
    116269IMGUI_API const char*   ImStrchrRange(const char* str_begin, const char* str_end, char c);
    117270IMGUI_API int           ImStrlenW(const ImWchar* str);
    118 IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
     271IMGUI_API const char*   ImStreolRange(const char* str, const char* str_end);                // End end-of-line
     272IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin);   // Find beginning-of-line
    119273IMGUI_API const char*   ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
     274IMGUI_API void          ImStrTrimBlanks(char* str);
     275IMGUI_API const char*   ImStrSkipBlank(const char* str);
    120276IMGUI_API int           ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3);
    121277IMGUI_API int           ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3);
    122 
    123 // Helpers: Math
    124 // We are keeping those not leaking to the user by default, in the case the user has implicit cast operators between ImVec2 and its own types (when IM_VEC2_CLASS_EXTRA is defined)
     278IMGUI_API const char*   ImParseFormatFindStart(const char* format);
     279IMGUI_API const char*   ImParseFormatFindEnd(const char* format);
     280IMGUI_API const char*   ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size);
     281IMGUI_API int           ImParseFormatPrecision(const char* format, int default_value);
     282static inline bool      ImCharIsBlankA(char c)          { return c == ' ' || c == '\t'; }
     283static inline bool      ImCharIsBlankW(unsigned int c)  { return c == ' ' || c == '\t' || c == 0x3000; }
     284
     285// Helpers: UTF-8 <> wchar conversions
     286IMGUI_API int           ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end);      // return output UTF-8 bytes count
     287IMGUI_API int           ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end);          // read one character. return input UTF-8 bytes count
     288IMGUI_API int           ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL);   // return input UTF-8 bytes count
     289IMGUI_API int           ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end);                            // return number of UTF-8 code-points (NOT bytes count)
     290IMGUI_API int           ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end);                        // return number of bytes to express one char in UTF-8
     291IMGUI_API int           ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end);                   // return number of bytes to express string in UTF-8
     292
     293// Helpers: ImVec2/ImVec4 operators
     294// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.)
     295// We unfortunately don't have a unary- operator for ImVec2 because this would needs to be defined inside the class itself.
    125296#ifdef IMGUI_DEFINE_MATH_OPERATORS
    126 static inline ImVec2 operator*(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x*rhs, lhs.y*rhs); }
    127 static inline ImVec2 operator/(const ImVec2& lhs, const float rhs) { return ImVec2(lhs.x / rhs, lhs.y / rhs); }
    128 static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
    129 static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
    130 static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x*rhs.x, lhs.y*rhs.y); }
    131 static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); }
    132 static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs) { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; }
    133 static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs) { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; }
    134 static inline ImVec2& operator*=(ImVec2& lhs, const float rhs) { lhs.x *= rhs; lhs.y *= rhs; return lhs; }
    135 static inline ImVec2& operator/=(ImVec2& lhs, const float rhs) { lhs.x /= rhs; lhs.y /= rhs; return lhs; }
    136 static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); }
    137 static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); }
    138 static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); }
    139 #endif
    140 
    141 static inline int    ImMin(int lhs, int rhs) { return lhs < rhs ? lhs : rhs; }
    142 static inline int    ImMax(int lhs, int rhs) { return lhs >= rhs ? lhs : rhs; }
    143 static inline float  ImMin(float lhs, float rhs) { return lhs < rhs ? lhs : rhs; }
    144 static inline float  ImMax(float lhs, float rhs) { return lhs >= rhs ? lhs : rhs; }
    145 static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); }
    146 static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); }
    147 static inline int    ImClamp(int v, int mn, int mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
    148 static inline float  ImClamp(float v, float mn, float mx) { return (v < mn) ? mn : (v > mx) ? mx : v; }
    149 static inline ImVec2 ImClamp(const ImVec2& f, const ImVec2& mn, ImVec2 mx) { return ImVec2(ImClamp(f.x, mn.x, mx.x), ImClamp(f.y, mn.y, mx.y)); }
    150 static inline float  ImSaturate(float f) { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }
    151 static inline void   ImSwap(int& a, int& b) { int tmp = a; a = b; b = tmp; }
    152 static inline void   ImSwap(float& a, float& b) { float tmp = a; a = b; b = tmp; }
    153 static inline int    ImLerp(int a, int b, float t) { return (int)(a + (b - a) * t); }
    154 static inline float  ImLerp(float a, float b, float t) { return a + (b - a) * t; }
    155 static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); }
    156 static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
    157 static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); }
    158 static inline float  ImLengthSqr(const ImVec2& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y; }
    159 static inline float  ImLengthSqr(const ImVec4& lhs) { return lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z + lhs.w*lhs.w; }
    160 static inline float  ImInvLength(const ImVec2& lhs, float fail_value) { float d = lhs.x*lhs.x + lhs.y*lhs.y; if (d > 0.0f) return 1.0f / sqrtf(d); return fail_value; }
    161 static inline float  ImFloor(float f) { return (float)(int)f; }
    162 static inline ImVec2 ImFloor(const ImVec2& v) { return ImVec2((float)(int)v.x, (float)(int)v.y); }
    163 static inline float  ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
    164 static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
    165 static inline float  ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
    166 static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
    167 
    168 //-----------------------------------------------------------------------------
    169 // Types
    170 //-----------------------------------------------------------------------------
    171 
    172 enum ImGuiButtonFlags_
    173 {
    174    ImGuiButtonFlags_Repeat = 1 << 0,   // hold to repeat
    175    ImGuiButtonFlags_PressedOnClickRelease = 1 << 1,   // return true on click + release on same item [DEFAULT if no PressedOn* flag is set]
    176    ImGuiButtonFlags_PressedOnClick = 1 << 2,   // return true on click (default requires click+release)
    177    ImGuiButtonFlags_PressedOnRelease = 1 << 3,   // return true on release (default requires click+release)
    178    ImGuiButtonFlags_PressedOnDoubleClick = 1 << 4,   // return true on double-click (default requires click+release)
    179    ImGuiButtonFlags_FlattenChildren = 1 << 5,   // allow interactions even if a child window is overlapping
    180    ImGuiButtonFlags_AllowItemOverlap = 1 << 6,   // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap()
    181    ImGuiButtonFlags_DontClosePopups = 1 << 7,   // disable automatically closing parent popup on press // [UNUSED]
    182    ImGuiButtonFlags_Disabled = 1 << 8,   // disable interactions
    183    ImGuiButtonFlags_AlignTextBaseLine = 1 << 9,   // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine
    184    ImGuiButtonFlags_NoKeyModifiers = 1 << 10,  // disable interaction if a key modifier is held
    185    ImGuiButtonFlags_NoHoldingActiveID = 1 << 11,  // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only)
    186    ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12,  // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers)
    187    ImGuiButtonFlags_NoNavFocus = 1 << 13   // don't override navigation focus when activated
    188 };
    189 
    190 enum ImGuiSliderFlags_
    191 {
    192    ImGuiSliderFlags_Vertical = 1 << 0
    193 };
    194 
    195 enum ImGuiColumnsFlags_
    196 {
    197    // Default: 0
    198    ImGuiColumnsFlags_NoBorder = 1 << 0,   // Disable column dividers
    199    ImGuiColumnsFlags_NoResize = 1 << 1,   // Disable resizing columns when clicking on the dividers
    200    ImGuiColumnsFlags_NoPreserveWidths = 1 << 2,   // Disable column width preservation when adjusting columns
    201    ImGuiColumnsFlags_NoForceWithinWindow = 1 << 3,   // Disable forcing columns to fit within window
    202    ImGuiColumnsFlags_GrowParentContentsSize = 1 << 4    // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove.
    203 };
    204 
    205 enum ImGuiSelectableFlagsPrivate_
    206 {
    207    // NB: need to be in sync with last value of ImGuiSelectableFlags_
    208    ImGuiSelectableFlags_Menu = 1 << 3,   // -> PressedOnClick
    209    ImGuiSelectableFlags_MenuItem = 1 << 4,   // -> PressedOnRelease
    210    ImGuiSelectableFlags_Disabled = 1 << 5,
    211    ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 6
    212 };
    213 
    214 enum ImGuiSeparatorFlags_
    215 {
    216    ImGuiSeparatorFlags_Horizontal = 1 << 0,   // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar
    217    ImGuiSeparatorFlags_Vertical = 1 << 1
    218 };
    219 
    220 // Storage for LastItem data
    221 enum ImGuiItemStatusFlags_
    222 {
    223    ImGuiItemStatusFlags_HoveredRect = 1 << 0,
    224    ImGuiItemStatusFlags_HasDisplayRect = 1 << 1
    225 };
    226 
    227 // FIXME: this is in development, not exposed/functional as a generic feature yet.
    228 enum ImGuiLayoutType_
    229 {
    230    ImGuiLayoutType_Vertical,
    231    ImGuiLayoutType_Horizontal
    232 };
    233 
    234 enum ImGuiAxis
    235 {
    236    ImGuiAxis_None = -1,
    237    ImGuiAxis_X = 0,
    238    ImGuiAxis_Y = 1
    239 };
    240 
    241 enum ImGuiPlotType
    242 {
    243    ImGuiPlotType_Lines,
    244    ImGuiPlotType_Histogram
    245 };
    246 
    247 enum ImGuiDataType
    248 {
    249    ImGuiDataType_Int32,
    250    ImGuiDataType_Uint32,
    251    ImGuiDataType_Float,
    252    ImGuiDataType_Double,
    253    ImGuiDataType_COUNT
    254 };
    255 
    256 enum ImGuiInputSource
    257 {
    258    ImGuiInputSource_None = 0,
    259    ImGuiInputSource_Mouse,
    260    ImGuiInputSource_Nav,
    261    ImGuiInputSource_NavKeyboard,   // Only used occasionally for storage, not tested/handled by most code
    262    ImGuiInputSource_NavGamepad,    // "
    263    ImGuiInputSource_COUNT
    264 };
    265 
    266 // FIXME-NAV: Clarify/expose various repeat delay/rate
    267 enum ImGuiInputReadMode
    268 {
    269    ImGuiInputReadMode_Down,
    270    ImGuiInputReadMode_Pressed,
    271    ImGuiInputReadMode_Released,
    272    ImGuiInputReadMode_Repeat,
    273    ImGuiInputReadMode_RepeatSlow,
    274    ImGuiInputReadMode_RepeatFast
    275 };
    276 
    277 enum ImGuiNavHighlightFlags_
    278 {
    279    ImGuiNavHighlightFlags_TypeDefault = 1 << 0,
    280    ImGuiNavHighlightFlags_TypeThin = 1 << 1,
    281    ImGuiNavHighlightFlags_AlwaysDraw = 1 << 2,
    282    ImGuiNavHighlightFlags_NoRounding = 1 << 3
    283 };
    284 
    285 enum ImGuiNavDirSourceFlags_
    286 {
    287    ImGuiNavDirSourceFlags_Keyboard = 1 << 0,
    288    ImGuiNavDirSourceFlags_PadDPad = 1 << 1,
    289    ImGuiNavDirSourceFlags_PadLStick = 1 << 2
    290 };
    291 
    292 enum ImGuiNavForward
    293 {
    294    ImGuiNavForward_None,
    295    ImGuiNavForward_ForwardQueued,
    296    ImGuiNavForward_ForwardActive
    297 };
    298 
    299 // 2D axis aligned bounding-box
    300 // NB: we can't rely on ImVec2 math operators being available here
     297static inline ImVec2 operator*(const ImVec2& lhs, const float rhs)              { return ImVec2(lhs.x * rhs, lhs.y * rhs); }
     298static inline ImVec2 operator/(const ImVec2& lhs, const float rhs)              { return ImVec2(lhs.x / rhs, lhs.y / rhs); }
     299static inline ImVec2 operator+(const ImVec2& lhs, const ImVec2& rhs)            { return ImVec2(lhs.x + rhs.x, lhs.y + rhs.y); }
     300static inline ImVec2 operator-(const ImVec2& lhs, const ImVec2& rhs)            { return ImVec2(lhs.x - rhs.x, lhs.y - rhs.y); }
     301static inline ImVec2 operator*(const ImVec2& lhs, const ImVec2& rhs)            { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
     302static inline ImVec2 operator/(const ImVec2& lhs, const ImVec2& rhs)            { return ImVec2(lhs.x / rhs.x, lhs.y / rhs.y); }
     303static inline ImVec2& operator*=(ImVec2& lhs, const float rhs)                  { lhs.x *= rhs; lhs.y *= rhs; return lhs; }
     304static inline ImVec2& operator/=(ImVec2& lhs, const float rhs)                  { lhs.x /= rhs; lhs.y /= rhs; return lhs; }
     305static inline ImVec2& operator+=(ImVec2& lhs, const ImVec2& rhs)                { lhs.x += rhs.x; lhs.y += rhs.y; return lhs; }
     306static inline ImVec2& operator-=(ImVec2& lhs, const ImVec2& rhs)                { lhs.x -= rhs.x; lhs.y -= rhs.y; return lhs; }
     307static inline ImVec2& operator*=(ImVec2& lhs, const ImVec2& rhs)                { lhs.x *= rhs.x; lhs.y *= rhs.y; return lhs; }
     308static inline ImVec2& operator/=(ImVec2& lhs, const ImVec2& rhs)                { lhs.x /= rhs.x; lhs.y /= rhs.y; return lhs; }
     309static inline ImVec4 operator+(const ImVec4& lhs, const ImVec4& rhs)            { return ImVec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w); }
     310static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs)            { return ImVec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w); }
     311static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs)            { return ImVec4(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z, lhs.w * rhs.w); }
     312#endif
     313
     314// Helpers: File System
     315#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
     316#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
     317typedef void* ImFileHandle;
     318static inline ImFileHandle  ImFileOpen(const char*, const char*)                    { return NULL; }
     319static inline bool          ImFileClose(ImFileHandle)                               { return false; }
     320static inline ImU64         ImFileGetSize(ImFileHandle)                             { return (ImU64)-1; }
     321static inline ImU64         ImFileRead(void*, ImU64, ImU64, ImFileHandle)           { return 0; }
     322static inline ImU64         ImFileWrite(const void*, ImU64, ImU64, ImFileHandle)    { return 0; }
     323#endif
     324#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
     325typedef FILE* ImFileHandle;
     326IMGUI_API ImFileHandle      ImFileOpen(const char* filename, const char* mode);
     327IMGUI_API bool              ImFileClose(ImFileHandle file);
     328IMGUI_API ImU64             ImFileGetSize(ImFileHandle file);
     329IMGUI_API ImU64             ImFileRead(void* data, ImU64 size, ImU64 count, ImFileHandle file);
     330IMGUI_API ImU64             ImFileWrite(const void* data, ImU64 size, ImU64 count, ImFileHandle file);
     331#else
     332#define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions
     333#endif
     334IMGUI_API void*             ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0);
     335
     336// Helpers: Maths
     337// - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy)
     338#ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS
     339#define ImFabs(X)           fabsf(X)
     340#define ImSqrt(X)           sqrtf(X)
     341#define ImFmod(X, Y)        fmodf((X), (Y))
     342#define ImCos(X)            cosf(X)
     343#define ImSin(X)            sinf(X)
     344#define ImAcos(X)           acosf(X)
     345#define ImAtan2(Y, X)       atan2f((Y), (X))
     346#define ImAtof(STR)         atof(STR)
     347#define ImFloorStd(X)       floorf(X)           // We already uses our own ImFloor() { return (float)(int)v } internally so the standard one wrapper is named differently (it's used by e.g. stb_truetype)
     348#define ImCeil(X)           ceilf(X)
     349static inline float  ImPow(float x, float y)    { return powf(x, y); }          // DragBehaviorT/SliderBehaviorT uses ImPow with either float/double and need the precision
     350static inline double ImPow(double x, double y)  { return pow(x, y); }
     351static inline float  ImLog(float x)             { return logf(x); }             // DragBehaviorT/SliderBehaviorT uses ImLog with either float/double and need the precision
     352static inline double ImLog(double x)            { return log(x); }
     353static inline float  ImAbs(float x)             { return fabsf(x); }
     354static inline double ImAbs(double x)            { return fabs(x); }
     355static inline float  ImSign(float x)            { return (x < 0.0f) ? -1.0f : ((x > 0.0f) ? 1.0f : 0.0f); } // Sign operator - returns -1, 0 or 1 based on sign of argument
     356static inline double ImSign(double x)           { return (x < 0.0) ? -1.0 : ((x > 0.0) ? 1.0 : 0.0); }
     357#endif
     358// - ImMin/ImMax/ImClamp/ImLerp/ImSwap are used by widgets which support variety of types: signed/unsigned int/long long float/double
     359// (Exceptionally using templates here but we could also redefine them for those types)
     360template<typename T> static inline T ImMin(T lhs, T rhs)                        { return lhs < rhs ? lhs : rhs; }
     361template<typename T> static inline T ImMax(T lhs, T rhs)                        { return lhs >= rhs ? lhs : rhs; }
     362template<typename T> static inline T ImClamp(T v, T mn, T mx)                   { return (v < mn) ? mn : (v > mx) ? mx : v; }
     363template<typename T> static inline T ImLerp(T a, T b, float t)                  { return (T)(a + (b - a) * t); }
     364template<typename T> static inline void ImSwap(T& a, T& b)                      { T tmp = a; a = b; b = tmp; }
     365template<typename T> static inline T ImAddClampOverflow(T a, T b, T mn, T mx)   { if (b < 0 && (a < mn - b)) return mn; if (b > 0 && (a > mx - b)) return mx; return a + b; }
     366template<typename T> static inline T ImSubClampOverflow(T a, T b, T mn, T mx)   { if (b > 0 && (a < mn + b)) return mn; if (b < 0 && (a > mx + b)) return mx; return a - b; }
     367// - Misc maths helpers
     368static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs)                { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); }
     369static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs)                { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); }
     370static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx)      { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); }
     371static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t)          { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); }
     372static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t)  { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
     373static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t)          { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); }
     374static inline float  ImSaturate(float f)                                        { return (f < 0.0f) ? 0.0f : (f > 1.0f) ? 1.0f : f; }
     375static inline float  ImLengthSqr(const ImVec2& lhs)                             { return (lhs.x * lhs.x) + (lhs.y * lhs.y); }
     376static inline float  ImLengthSqr(const ImVec4& lhs)                             { return (lhs.x * lhs.x) + (lhs.y * lhs.y) + (lhs.z * lhs.z) + (lhs.w * lhs.w); }
     377static inline float  ImInvLength(const ImVec2& lhs, float fail_value)           { float d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if (d > 0.0f) return 1.0f / ImSqrt(d); return fail_value; }
     378static inline float  ImFloor(float f)                                           { return (float)(int)(f); }
     379static inline ImVec2 ImFloor(const ImVec2& v)                                   { return ImVec2((float)(int)(v.x), (float)(int)(v.y)); }
     380static inline int    ImModPositive(int a, int b)                                { return (a + b) % b; }
     381static inline float  ImDot(const ImVec2& a, const ImVec2& b)                    { return a.x * b.x + a.y * b.y; }
     382static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a)        { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
     383static inline float  ImLinearSweep(float current, float target, float speed)    { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
     384static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs)                { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
     385
     386// Helpers: Geometry
     387IMGUI_API ImVec2     ImBezierCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t);                                         // Cubic Bezier
     388IMGUI_API ImVec2     ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments);       // For curves with explicit number of segments
     389IMGUI_API ImVec2     ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol
     390IMGUI_API ImVec2     ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);
     391IMGUI_API bool       ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
     392IMGUI_API ImVec2     ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
     393IMGUI_API void       ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w);
     394inline float         ImTriangleArea(const ImVec2& a, const ImVec2& b, const ImVec2& c) { return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5f; }
     395IMGUI_API ImGuiDir   ImGetDirQuadrantFromDelta(float dx, float dy);
     396
     397// Helper: ImVec1 (1D vector)
     398// (this odd construct is used to facilitate the transition between 1D and 2D, and the maintenance of some branches/patches)
     399struct ImVec1
     400{
     401    float   x;
     402    ImVec1()         { x = 0.0f; }
     403    ImVec1(float _x) { x = _x; }
     404};
     405
     406// Helper: ImVec2ih (2D vector, half-size integer, for long-term packed storage)
     407struct ImVec2ih
     408{
     409    short   x, y;
     410    ImVec2ih()                           { x = y = 0; }
     411    ImVec2ih(short _x, short _y)         { x = _x; y = _y; }
     412    explicit ImVec2ih(const ImVec2& rhs) { x = (short)rhs.x; y = (short)rhs.y; }
     413};
     414
     415// Helper: ImRect (2D axis aligned bounding-box)
     416// NB: we can't rely on ImVec2 math operators being available here!
    301417struct IMGUI_API ImRect
    302418{
    303    ImVec2      Min;    // Upper-left
    304    ImVec2      Max;    // Lower-right
    305 
    306    ImRect() : Min(FLT_MAX, FLT_MAX), Max(-FLT_MAX, -FLT_MAX) {}
    307    ImRect(const ImVec2& min, const ImVec2& max) : Min(min), Max(max) {}
    308    ImRect(const ImVec4& v) : Min(v.x, v.y), Max(v.z, v.w) {}
    309    ImRect(float x1, float y1, float x2, float y2) : Min(x1, y1), Max(x2, y2) {}
    310 
    311    ImVec2      GetCenter() const { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); }
    312    ImVec2      GetSize() const { return ImVec2(Max.x - Min.x, Max.y - Min.y); }
    313    float       GetWidth() const { return Max.x - Min.x; }
    314    float       GetHeight() const { return Max.y - Min.y; }
    315    ImVec2      GetTL() const { return Min; }                   // Top-left
    316    ImVec2      GetTR() const { return ImVec2(Max.x, Min.y); }  // Top-right
    317    ImVec2      GetBL() const { return ImVec2(Min.x, Max.y); }  // Bottom-left
    318    ImVec2      GetBR() const { return Max; }                   // Bottom-right
    319    bool        Contains(const ImVec2& p) const { return p.x >= Min.x && p.y >= Min.y && p.x     <  Max.x && p.y     <  Max.y; }
    320    bool        Contains(const ImRect& r) const { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; }
    321    bool        Overlaps(const ImRect& r) const { return r.Min.y <  Max.y && r.Max.y >  Min.y && r.Min.x <  Max.x && r.Max.x >  Min.x; }
    322    void        Add(const ImVec2& p) { if (Min.x > p.x)     Min.x = p.x;     if (Min.y > p.y)     Min.y = p.y;     if (Max.x < p.x)     Max.x = p.x;     if (Max.y < p.y)     Max.y = p.y; }
    323    void        Add(const ImRect& r) { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; }
    324    void        Expand(const float amount) { Min.x -= amount;   Min.y -= amount;   Max.x += amount;   Max.y += amount; }
    325    void        Expand(const ImVec2& amount) { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; }
    326    void        Translate(const ImVec2& d) { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; }
    327    void        ClipWith(const ImRect& r) { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); }                   // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display.
    328    void        ClipWithFull(const ImRect& r) { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped.
    329    void        Floor() { Min.x = (float)(int)Min.x; Min.y = (float)(int)Min.y; Max.x = (float)(int)Max.x; Max.y = (float)(int)Max.y; }
    330    bool        IsInverted() const { return Min.x > Max.x || Min.y > Max.y; }
    331 };
    332 
    333 // Stacked color modifier, backup of modified data so we can restore it
    334 struct ImGuiColMod
    335 {
    336    ImGuiCol    Col;
    337    ImVec4      BackupValue;
    338 };
    339 
    340 // Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.
    341 struct ImGuiStyleMod
    342 {
    343    ImGuiStyleVar   VarIdx;
    344    union { int BackupInt[2]; float BackupFloat[2]; };
    345    ImGuiStyleMod(ImGuiStyleVar idx, int v) { VarIdx = idx; BackupInt[0] = v; }
    346    ImGuiStyleMod(ImGuiStyleVar idx, float v) { VarIdx = idx; BackupFloat[0] = v; }
    347    ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v) { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; }
    348 };
    349 
    350 // Stacked data for BeginGroup()/EndGroup()
    351 struct ImGuiGroupData
    352 {
    353    ImVec2      BackupCursorPos;
    354    ImVec2      BackupCursorMaxPos;
    355    float       BackupIndentX;
    356    float       BackupGroupOffsetX;
    357    float       BackupCurrentLineHeight;
    358    float       BackupCurrentLineTextBaseOffset;
    359    float       BackupLogLinePosY;
    360    bool        BackupActiveIdIsAlive;
    361    bool        AdvanceCursor;
    362 };
    363 
    364 // Simple column measurement currently used for MenuItem() only. This is very short-sighted/throw-away code and NOT a generic helper.
    365 struct IMGUI_API ImGuiMenuColumns
    366 {
    367    int         Count;
    368    float       Spacing;
    369    float       Width, NextWidth;
    370    float       Pos[4], NextWidths[4];
    371 
    372    ImGuiMenuColumns();
    373    void        Update(int count, float spacing, bool clear);
    374    float       DeclColumns(float w0, float w1, float w2);
    375    float       CalcExtraSpace(float avail_w);
    376 };
    377 
    378 // Internal state of the currently focused/edited text input box
    379 struct IMGUI_API ImGuiTextEditState
    380 {
    381    ImGuiID             Id;                         // widget id owning the text state
    382    ImVector<ImWchar>   Text;                       // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
    383    ImVector<char>      InitialText;                // backup of end-user buffer at the time of focus (in UTF-8, unaltered)
    384    ImVector<char>      TempTextBuffer;
    385    int                 CurLenA, CurLenW;           // we need to maintain our buffer length in both UTF-8 and wchar format.
    386    int                 BufSizeA;                   // end-user buffer size
    387    float               ScrollX;
    388    ImGuiStb::STB_TexteditState   StbState;
    389    float               CursorAnim;
    390    bool                CursorFollow;
    391    bool                SelectedAllMouseLock;
    392 
    393    ImGuiTextEditState() { memset(this, 0, sizeof(*this)); }
    394    void                CursorAnimReset() { CursorAnim = -0.30f; }                                   // After a user-input the cursor stays on for a while without blinking
    395    void                CursorClamp() { StbState.cursor = ImMin(StbState.cursor, CurLenW); StbState.select_start = ImMin(StbState.select_start, CurLenW); StbState.select_end = ImMin(StbState.select_end, CurLenW); }
    396    bool                HasSelection() const { return StbState.select_start != StbState.select_end; }
    397    void                ClearSelection() { StbState.select_start = StbState.select_end = StbState.cursor; }
    398    void                SelectAll() { StbState.select_start = 0; StbState.cursor = StbState.select_end = CurLenW; StbState.has_preferred_x = false; }
    399    void                OnKeyPressed(int key);
    400 };
    401 
    402 // Data saved in imgui.ini file
    403 struct ImGuiWindowSettings
    404 {
    405    char*       Name;
    406    ImGuiID     Id;
    407    ImVec2      Pos;
    408    ImVec2      Size;
    409    bool        Collapsed;
    410 
    411    ImGuiWindowSettings() { Name = NULL; Id = 0; Pos = Size = ImVec2(0, 0); Collapsed = false; }
    412 };
    413 
    414 struct ImGuiSettingsHandler
    415 {
    416    const char* TypeName;   // Short description stored in .ini file. Disallowed characters: '[' ']' 
    417    ImGuiID     TypeHash;   // == ImHash(TypeName, 0, 0)
    418    void*       (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name);              // Read: Called when entering into a new ini entry e.g. "[Window][Name]"
    419    void(*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry
    420    void(*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf);      // Write: Output every entries into 'out_buf'
    421    void*       UserData;
    422 
    423    ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); }
    424 };
    425 
    426 // Storage for current popup stack
    427 struct ImGuiPopupRef
    428 {
    429    ImGuiID             PopupId;        // Set on OpenPopup()
    430    ImGuiWindow*        Window;         // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup()
    431    ImGuiWindow*        ParentWindow;   // Set on OpenPopup()
    432    int                 OpenFrameCount; // Set on OpenPopup()
    433    ImGuiID             OpenParentId;   // Set on OpenPopup(), we need this to differenciate multiple menu sets from each others (e.g. inside menu bar vs loose menu items)
    434    ImVec2              OpenPopupPos;   // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse)
    435    ImVec2              OpenMousePos;   // Set on OpenPopup(), copy of mouse position at the time of opening popup
    436 };
    437 
    438 struct ImGuiColumnData
    439 {
    440    float               OffsetNorm;         // Column start offset, normalized 0.0 (far left) -> 1.0 (far right)
    441    float               OffsetNormBeforeResize;
    442    ImGuiColumnsFlags   Flags;              // Not exposed
    443    ImRect              ClipRect;
    444 
    445    ImGuiColumnData() { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = 0; }
    446 };
    447 
    448 struct ImGuiColumnsSet
    449 {
    450    ImGuiID             ID;
    451    ImGuiColumnsFlags   Flags;
    452    bool                IsFirstFrame;
    453    bool                IsBeingResized;
    454    int                 Current;
    455    int                 Count;
    456    float               MinX, MaxX;
    457    float               LineMinY, LineMaxY;
    458    float               StartPosY;          // Copy of CursorPos
    459    float               StartMaxPosX;       // Copy of CursorMaxPos
    460    ImVector<ImGuiColumnData> Columns;
    461 
    462    ImGuiColumnsSet() { Clear(); }
    463    void Clear()
    464    {
    465       ID = 0;
    466       Flags = 0;
    467       IsFirstFrame = false;
    468       IsBeingResized = false;
    469       Current = 0;
    470       Count = 1;
    471       MinX = MaxX = 0.0f;
    472       LineMinY = LineMaxY = 0.0f;
    473       StartPosY = 0.0f;
    474       StartMaxPosX = 0.0f;
    475       Columns.clear();
    476    }
    477 };
    478 
     419    ImVec2      Min;    // Upper-left
     420    ImVec2      Max;    // Lower-right
     421
     422    ImRect()                                        : Min(0.0f, 0.0f), Max(0.0f, 0.0f)  {}
     423    ImRect(const ImVec2& min, const ImVec2& max)    : Min(min), Max(max)                {}
     424    ImRect(const ImVec4& v)                         : Min(v.x, v.y), Max(v.z, v.w)      {}
     425    ImRect(float x1, float y1, float x2, float y2)  : Min(x1, y1), Max(x2, y2)          {}
     426
     427    ImVec2      GetCenter() const                   { return ImVec2((Min.x + Max.x) * 0.5f, (Min.y + Max.y) * 0.5f); }
     428    ImVec2      GetSize() const                     { return ImVec2(Max.x - Min.x, Max.y - Min.y); }
     429    float       GetWidth() const                    { return Max.x - Min.x; }
     430    float       GetHeight() const                   { return Max.y - Min.y; }
     431    ImVec2      GetTL() const                       { return Min; }                   // Top-left
     432    ImVec2      GetTR() const                       { return ImVec2(Max.x, Min.y); }  // Top-right
     433    ImVec2      GetBL() const                       { return ImVec2(Min.x, Max.y); }  // Bottom-left
     434    ImVec2      GetBR() const                       { return Max; }                   // Bottom-right
     435    bool        Contains(const ImVec2& p) const     { return p.x     >= Min.x && p.y     >= Min.y && p.x     <  Max.x && p.y     <  Max.y; }
     436    bool        Contains(const ImRect& r) const     { return r.Min.x >= Min.x && r.Min.y >= Min.y && r.Max.x <= Max.x && r.Max.y <= Max.y; }
     437    bool        Overlaps(const ImRect& r) const     { return r.Min.y <  Max.y && r.Max.y >  Min.y && r.Min.x <  Max.x && r.Max.x >  Min.x; }
     438    void        Add(const ImVec2& p)                { if (Min.x > p.x)     Min.x = p.x;     if (Min.y > p.y)     Min.y = p.y;     if (Max.x < p.x)     Max.x = p.x;     if (Max.y < p.y)     Max.y = p.y; }
     439    void        Add(const ImRect& r)                { if (Min.x > r.Min.x) Min.x = r.Min.x; if (Min.y > r.Min.y) Min.y = r.Min.y; if (Max.x < r.Max.x) Max.x = r.Max.x; if (Max.y < r.Max.y) Max.y = r.Max.y; }
     440    void        Expand(const float amount)          { Min.x -= amount;   Min.y -= amount;   Max.x += amount;   Max.y += amount; }
     441    void        Expand(const ImVec2& amount)        { Min.x -= amount.x; Min.y -= amount.y; Max.x += amount.x; Max.y += amount.y; }
     442    void        Translate(const ImVec2& d)          { Min.x += d.x; Min.y += d.y; Max.x += d.x; Max.y += d.y; }
     443    void        TranslateX(float dx)                { Min.x += dx; Max.x += dx; }
     444    void        TranslateY(float dy)                { Min.y += dy; Max.y += dy; }
     445    void        ClipWith(const ImRect& r)           { Min = ImMax(Min, r.Min); Max = ImMin(Max, r.Max); }                   // Simple version, may lead to an inverted rectangle, which is fine for Contains/Overlaps test but not for display.
     446    void        ClipWithFull(const ImRect& r)       { Min = ImClamp(Min, r.Min, r.Max); Max = ImClamp(Max, r.Min, r.Max); } // Full version, ensure both points are fully clipped.
     447    void        Floor()                             { Min.x = IM_FLOOR(Min.x); Min.y = IM_FLOOR(Min.y); Max.x = IM_FLOOR(Max.x); Max.y = IM_FLOOR(Max.y); }
     448    bool        IsInverted() const                  { return Min.x > Max.x || Min.y > Max.y; }
     449    ImVec4      ToVec4() const                      { return ImVec4(Min.x, Min.y, Max.x, Max.y); }
     450};
     451
     452// Helper: ImBitArray
     453inline bool          ImBitArrayTestBit(const ImU32* arr, int n)         { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; }
     454inline void          ImBitArrayClearBit(ImU32* arr, int n)              { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; }
     455inline void          ImBitArraySetBit(ImU32* arr, int n)                { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; }
     456inline void          ImBitArraySetBitRange(ImU32* arr, int n, int n2)
     457{
     458    while (n <= n2)
     459    {
     460        int a_mod = (n & 31);
     461        int b_mod = ((n2 >= n + 31) ? 31 : (n2 & 31)) + 1;
     462        ImU32 mask = (ImU32)(((ImU64)1 << b_mod) - 1) & ~(ImU32)(((ImU64)1 << a_mod) - 1);
     463        arr[n >> 5] |= mask;
     464        n = (n + 32) & ~31;
     465    }
     466}
     467
     468// Helper: ImBitVector
     469// Store 1-bit per value.
     470struct IMGUI_API ImBitVector
     471{
     472    ImVector<ImU32> Storage;
     473    void            Create(int sz)              { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
     474    void            Clear()                     { Storage.clear(); }
     475    bool            TestBit(int n) const        { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); }
     476    void            SetBit(int n)               { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); }
     477    void            ClearBit(int n)             { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); }
     478};
     479
     480// Helper: ImPool<>
     481// Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer,
     482// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object.
     483typedef int ImPoolIdx;
     484template<typename T>
     485struct IMGUI_API ImPool
     486{
     487    ImVector<T>     Buf;        // Contiguous data
     488    ImGuiStorage    Map;        // ID->Index
     489    ImPoolIdx       FreeIdx;    // Next free idx to use
     490
     491    ImPool()    { FreeIdx = 0; }
     492    ~ImPool()   { Clear(); }
     493    T*          GetByKey(ImGuiID key)               { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; }
     494    T*          GetByIndex(ImPoolIdx n)             { return &Buf[n]; }
     495    ImPoolIdx   GetIndex(const T* p) const          { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.Data); }
     496    T*          GetOrAddByKey(ImGuiID key)          { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); }
     497    bool        Contains(const T* p) const          { return (p >= Buf.Data && p < Buf.Data + Buf.Size); }
     498    void        Clear()                             { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.clear(); FreeIdx = 0; }
     499    T*          Add()                               { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); return &Buf[idx]; }
     500    void        Remove(ImGuiID key, const T* p)     { Remove(key, GetIndex(p)); }
     501    void        Remove(ImGuiID key, ImPoolIdx idx)  { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); }
     502    void        Reserve(int capacity)               { Buf.reserve(capacity); Map.Data.reserve(capacity); }
     503    int         GetSize() const                     { return Buf.Size; }
     504};
     505
     506// Helper: ImChunkStream<>
     507// Build and iterate a contiguous stream of variable-sized structures.
     508// This is used by Settings to store persistent data while reducing allocation count.
     509// We store the chunk size first, and align the final size on 4 bytes boundaries (this what the '(X + 3) & ~3' statement is for)
     510// The tedious/zealous amount of casting is to avoid -Wcast-align warnings.
     511template<typename T>
     512struct IMGUI_API ImChunkStream
     513{
     514    ImVector<char>  Buf;
     515
     516    void    clear()                     { Buf.clear(); }
     517    bool    empty() const               { return Buf.Size == 0; }
     518    int     size() const                { return Buf.Size; }
     519    T*      alloc_chunk(size_t sz)      { size_t HDR_SZ = 4; sz = ((HDR_SZ + sz) + 3u) & ~3u; int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); }
     520    T*      begin()                     { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); }
     521    T*      next_chunk(T* p)            { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; }
     522    int     chunk_size(const T* p)      { return ((const int*)p)[-1]; }
     523    T*      end()                       { return (T*)(void*)(Buf.Data + Buf.Size); }
     524    int     offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; }
     525    T*      ptr_from_offset(int off)    { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); }
     526};
     527
     528//-----------------------------------------------------------------------------
     529// [SECTION] ImDrawList support
     530//-----------------------------------------------------------------------------
     531
     532// ImDrawList: Helper function to calculate a circle's segment count given its radius and a "maximum error" value.
     533#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN                     12
     534#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX                     512
     535#define IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(_RAD,_MAXERROR)    ImClamp((int)((IM_PI * 2.0f) / ImAcos(((_RAD) - (_MAXERROR)) / (_RAD))), IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MIN, IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_MAX)
     536
     537// ImDrawList: You may set this to higher values (e.g. 2 or 3) to increase tessellation of fast rounded corners path.
     538#ifndef IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER
     539#define IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER             1
     540#endif
     541
     542// Data shared between all ImDrawList instances
     543// You may want to create your own instance of this if you want to use ImDrawList completely without ImGui. In that case, watch out for future changes to this structure.
    479544struct IMGUI_API ImDrawListSharedData
    480545{
    481    ImVec2          TexUvWhitePixel;            // UV of white pixel in the atlas
    482    ImFont*         Font;                       // Current/default font (optional, for simplified AddText overload)
    483    float           FontSize;                   // Current/default font size (optional, for simplified AddText overload)
    484    float           CurveTessellationTol;
    485    ImVec4          ClipRectFullscreen;         // Value for PushClipRectFullscreen()
    486 
    487                                                // Const data
    488                                                // FIXME: Bake rounded corners fill/borders in atlas
    489    ImVec2          CircleVtx12[12];
    490 
    491    ImDrawListSharedData();
     546    ImVec2          TexUvWhitePixel;            // UV of white pixel in the atlas
     547    ImFont*         Font;                       // Current/default font (optional, for simplified AddText overload)
     548    float           FontSize;                   // Current/default font size (optional, for simplified AddText overload)
     549    float           CurveTessellationTol;       // Tessellation tolerance when using PathBezierCurveTo()
     550    float           CircleSegmentMaxError;      // Number of circle segments to use per pixel of radius for AddCircle() etc
     551    ImVec4          ClipRectFullscreen;         // Value for PushClipRectFullscreen()
     552    ImDrawListFlags InitialFlags;               // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
     553
     554    // [Internal] Lookup tables
     555    ImVec2          ArcFastVtx[12 * IM_DRAWLIST_ARCFAST_TESSELLATION_MULTIPLIER];  // FIXME: Bake rounded corners fill/borders in atlas
     556    ImU8            CircleSegmentCounts[64];    // Precomputed segment count for given radius (array index + 1) before we calculate it dynamically (to avoid calculation overhead)
     557    const ImVec4*   TexUvLines;                 // UV of anti-aliased lines in the atlas
     558
     559    ImDrawListSharedData();
     560    void SetCircleSegmentMaxError(float max_error);
    492561};
    493562
    494563struct ImDrawDataBuilder
    495564{
    496    ImVector<ImDrawList*>   Layers[2];           // Global layers for: regular, tooltip
    497 
    498    void Clear() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); }
    499    void ClearFreeMemory() { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); }
    500    IMGUI_API void FlattenIntoSingleLayer();
    501 };
    502 
    503 struct ImGuiNavMoveResult
    504 {
    505    ImGuiID       ID;           // Best candidate
    506    ImGuiID       ParentID;     // Best candidate window->IDStack.back() - to compare context
    507    ImGuiWindow*  Window;       // Best candidate window
    508    float         DistBox;      // Best candidate box distance to current NavId
    509    float         DistCenter;   // Best candidate center distance to current NavId
    510    float         DistAxial;
    511    ImRect        RectRel;      // Best candidate bounding box in window relative space
    512 
    513    ImGuiNavMoveResult() { Clear(); }
    514    void Clear() { ID = ParentID = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); }
    515 };
    516 
    517 // Storage for SetNexWindow** functions
    518 struct ImGuiNextWindowData
    519 {
    520    ImGuiCond               PosCond;
    521    ImGuiCond               SizeCond;
    522    ImGuiCond               ContentSizeCond;
    523    ImGuiCond               CollapsedCond;
    524    ImGuiCond               SizeConstraintCond;
    525    ImGuiCond               FocusCond;
    526    ImGuiCond               BgAlphaCond;
    527    ImVec2                  PosVal;
    528    ImVec2                  PosPivotVal;
    529    ImVec2                  SizeVal;
    530    ImVec2                  ContentSizeVal;
    531    bool                    CollapsedVal;
    532    ImRect                  SizeConstraintRect;
    533    ImGuiSizeCallback       SizeCallback;
    534    void*                   SizeCallbackUserData;
    535    float                   BgAlphaVal;
    536    ImVec2                  MenuBarOffsetMinVal;                // This is not exposed publicly, so we don't clear it.
    537 
    538    ImGuiNextWindowData()
    539    {
    540       PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0;
    541       PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f);
    542       ContentSizeVal = ImVec2(0.0f, 0.0f);
    543       CollapsedVal = false;
    544       SizeConstraintRect = ImRect();
    545       SizeCallback = NULL;
    546       SizeCallbackUserData = NULL;
    547       BgAlphaVal = FLT_MAX;
    548       MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
    549    }
    550 
    551    void    Clear()
    552    {
    553       PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0;
    554    }
    555 };
    556 
    557 // Main state for ImGui
    558 struct ImGuiContext
    559 {
    560    bool                    Initialized;
    561    bool                    FontAtlasOwnedByContext;            // Io.Fonts-> is owned by the ImGuiContext and will be destructed along with it.
    562    ImGuiIO                 IO;
    563    ImGuiStyle              Style;
    564    ImFont*                 Font;                               // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()
    565    float                   FontSize;                           // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
    566    float                   FontBaseSize;                       // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
    567    ImDrawListSharedData    DrawListSharedData;
    568 
    569    float                   Time;
    570    int                     FrameCount;
    571    int                     FrameCountEnded;
    572    int                     FrameCountRendered;
    573    ImVector<ImGuiWindow*>  Windows;
    574    ImVector<ImGuiWindow*>  WindowsSortBuffer;
    575    ImVector<ImGuiWindow*>  CurrentWindowStack;
    576    ImGuiStorage            WindowsById;
    577    int                     WindowsActiveCount;
    578    ImGuiWindow*            CurrentWindow;                      // Being drawn into
    579    ImGuiWindow*            HoveredWindow;                      // Will catch mouse inputs
    580    ImGuiWindow*            HoveredRootWindow;                  // Will catch mouse inputs (for focus/move only)
    581    ImGuiID                 HoveredId;                          // Hovered widget
    582    bool                    HoveredIdAllowOverlap;
    583    ImGuiID                 HoveredIdPreviousFrame;
    584    float                   HoveredIdTimer;
    585    ImGuiID                 ActiveId;                           // Active widget
    586    ImGuiID                 ActiveIdPreviousFrame;
    587    float                   ActiveIdTimer;
    588    bool                    ActiveIdIsAlive;                    // Active widget has been seen this frame
    589    bool                    ActiveIdIsJustActivated;            // Set at the time of activation for one frame
    590    bool                    ActiveIdAllowOverlap;               // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always)
    591    int                     ActiveIdAllowNavDirFlags;           // Active widget allows using directional navigation (e.g. can activate a button and move away from it)
    592    ImVec2                  ActiveIdClickOffset;                // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)
    593    ImGuiWindow*            ActiveIdWindow;
    594    ImGuiInputSource        ActiveIdSource;                     // Activating with mouse or nav (gamepad/keyboard)
    595    ImGuiWindow*            MovingWindow;                       // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow.
    596    ImVector<ImGuiColMod>   ColorModifiers;                     // Stack for PushStyleColor()/PopStyleColor()
    597    ImVector<ImGuiStyleMod> StyleModifiers;                     // Stack for PushStyleVar()/PopStyleVar()
    598    ImVector<ImFont*>       FontStack;                          // Stack for PushFont()/PopFont()
    599    ImVector<ImGuiPopupRef> OpenPopupStack;                     // Which popups are open (persistent)
    600    ImVector<ImGuiPopupRef> CurrentPopupStack;                  // Which level of BeginPopup() we are in (reset every frame)
    601    ImGuiNextWindowData     NextWindowData;                     // Storage for SetNextWindow** functions
    602    bool                    NextTreeNodeOpenVal;                // Storage for SetNextTreeNode** functions
    603    ImGuiCond               NextTreeNodeOpenCond;
    604 
    605    // Navigation data (for gamepad/keyboard)
    606    ImGuiWindow*            NavWindow;                          // Focused window for navigation. Could be called 'FocusWindow'
    607    ImGuiID                 NavId;                              // Focused item for navigation
    608    ImGuiID                 NavActivateId;                      // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem()
    609    ImGuiID                 NavActivateDownId;                  // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0
    610    ImGuiID                 NavActivatePressedId;               // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0
    611    ImGuiID                 NavInputId;                         // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0
    612    ImGuiID                 NavJustTabbedId;                    // Just tabbed to this id.
    613    ImGuiID                 NavJustMovedToId;                   // Just navigated to this id (result of a successfully MoveRequest)
    614    ImGuiID                 NavNextActivateId;                  // Set by ActivateItem(), queued until next frame
    615    ImGuiInputSource        NavInputSource;                     // Keyboard or Gamepad mode?
    616    ImRect                  NavScoringRectScreen;               // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring.
    617    int                     NavScoringCount;                    // Metrics for debugging
    618    ImGuiWindow*            NavWindowingTarget;                 // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most.
    619    float                   NavWindowingHighlightTimer;
    620    float                   NavWindowingHighlightAlpha;
    621    bool                    NavWindowingToggleLayer;
    622    int                     NavLayer;                           // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
    623    int                     NavIdTabCounter;                    // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing
    624    bool                    NavIdIsAlive;                       // Nav widget has been seen this frame ~~ NavRefRectRel is valid
    625    bool                    NavMousePosDirty;                   // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
    626    bool                    NavDisableHighlight;                // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover)
    627    bool                    NavDisableMouseHover;               // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again.
    628    bool                    NavAnyRequest;                      // ~~ NavMoveRequest || NavInitRequest
    629    bool                    NavInitRequest;                     // Init request for appearing window to select first item
    630    bool                    NavInitRequestFromMove;
    631    ImGuiID                 NavInitResultId;
    632    ImRect                  NavInitResultRectRel;
    633    bool                    NavMoveFromClampedRefRect;          // Set by manual scrolling, if we scroll to a point where NavId isn't visible we reset navigation from visible items
    634    bool                    NavMoveRequest;                     // Move request for this frame
    635    ImGuiNavForward         NavMoveRequestForward;              // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu)
    636    ImGuiDir                NavMoveDir, NavMoveDirLast;         // Direction of the move request (left/right/up/down), direction of the previous move request
    637    ImGuiNavMoveResult      NavMoveResultLocal;                 // Best move request candidate within NavWindow
    638    ImGuiNavMoveResult      NavMoveResultOther;                 // Best move request candidate within NavWindow's flattened hierarchy (when using the NavFlattened flag)
    639 
    640                                                                // Render
    641    ImDrawData              DrawData;                           // Main ImDrawData instance to pass render information to the user
    642    ImDrawDataBuilder       DrawDataBuilder;
    643    float                   ModalWindowDarkeningRatio;
    644    ImDrawList              OverlayDrawList;                    // Optional software render of mouse cursors, if io.MouseDrawCursor is set + a few debug overlays
    645    ImGuiMouseCursor        MouseCursor;
    646 
    647    // Drag and Drop
    648    bool                    DragDropActive;
    649    ImGuiDragDropFlags      DragDropSourceFlags;
    650    int                     DragDropMouseButton;
    651    ImGuiPayload            DragDropPayload;
    652    ImRect                  DragDropTargetRect;
    653    ImGuiID                 DragDropTargetId;
    654    float                   DragDropAcceptIdCurrRectSurface;
    655    ImGuiID                 DragDropAcceptIdCurr;               // Target item id (set at the time of accepting the payload)
    656    ImGuiID                 DragDropAcceptIdPrev;               // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets)
    657    int                     DragDropAcceptFrameCount;           // Last time a target expressed a desire to accept the source
    658    ImVector<unsigned char> DragDropPayloadBufHeap;             // We don't expose the ImVector<> directly
    659    unsigned char           DragDropPayloadBufLocal[8];         // Local buffer for small payloads
    660 
    661                                                                // Widget state
    662    ImGuiTextEditState      InputTextState;
    663    ImFont                  InputTextPasswordFont;
    664    ImGuiID                 ScalarAsInputTextId;                // Temporary text input when CTRL+clicking on a slider, etc.
    665    ImGuiColorEditFlags     ColorEditOptions;                   // Store user options for color edit widgets
    666    ImVec4                  ColorPickerRef;
    667    float                   DragCurrentValue;                   // Currently dragged value, always float, not rounded by end-user precision settings
    668    ImVec2                  DragLastMouseDelta;
    669    float                   DragSpeedDefaultRatio;              // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio
    670    float                   DragSpeedScaleSlow;
    671    float                   DragSpeedScaleFast;
    672    ImVec2                  ScrollbarClickDeltaToGrabCenter;    // Distance between mouse and center of grab box, normalized in parent space. Use storage?
    673    int                     TooltipOverrideCount;
    674    ImVector<char>          PrivateClipboard;                   // If no custom clipboard handler is defined
    675    ImVec2                  PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor
    676 
    677                                                                // Settings
    678    bool                           SettingsLoaded;
    679    float                          SettingsDirtyTimer;          // Save .ini Settings on disk when time reaches zero
    680    ImVector<ImGuiWindowSettings>  SettingsWindows;             // .ini settings for ImGuiWindow
    681    ImVector<ImGuiSettingsHandler> SettingsHandlers;            // List of .ini settings handlers
    682 
    683                                                                // Logging
    684    bool                    LogEnabled;
    685    FILE*                   LogFile;                            // If != NULL log to stdout/ file
    686    ImGuiTextBuffer*        LogClipboard;                       // Else log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators.
    687    int                     LogStartDepth;
    688    int                     LogAutoExpandMaxDepth;
    689 
    690    // Misc
    691    float                   FramerateSecPerFrame[120];          // Calculate estimate of framerate for user over the last 2 seconds.
    692    int                     FramerateSecPerFrameIdx;
    693    float                   FramerateSecPerFrameAccum;
    694    int                     WantCaptureMouseNextFrame;          // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags
    695    int                     WantCaptureKeyboardNextFrame;
    696    int                     WantTextInputNextFrame;
    697    char                    TempBuffer[1024 * 3 + 1];               // Temporary text buffer
    698 
    699    ImGuiContext(ImFontAtlas* shared_font_atlas) : OverlayDrawList(NULL)
    700    {
    701       Initialized = false;
    702       Font = NULL;
    703       FontSize = FontBaseSize = 0.0f;
    704       FontAtlasOwnedByContext = shared_font_atlas ? false : true;
    705       IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
    706 
    707       Time = 0.0f;
    708       FrameCount = 0;
    709       FrameCountEnded = FrameCountRendered = -1;
    710       WindowsActiveCount = 0;
    711       CurrentWindow = NULL;
    712       HoveredWindow = NULL;
    713       HoveredRootWindow = NULL;
    714       HoveredId = 0;
    715       HoveredIdAllowOverlap = false;
    716       HoveredIdPreviousFrame = 0;
    717       HoveredIdTimer = 0.0f;
    718       ActiveId = 0;
    719       ActiveIdPreviousFrame = 0;
    720       ActiveIdTimer = 0.0f;
    721       ActiveIdIsAlive = false;
    722       ActiveIdIsJustActivated = false;
    723       ActiveIdAllowOverlap = false;
    724       ActiveIdAllowNavDirFlags = 0;
    725       ActiveIdClickOffset = ImVec2(-1, -1);
    726       ActiveIdWindow = NULL;
    727       ActiveIdSource = ImGuiInputSource_None;
    728       MovingWindow = NULL;
    729       NextTreeNodeOpenVal = false;
    730       NextTreeNodeOpenCond = 0;
    731 
    732       NavWindow = NULL;
    733       NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0;
    734       NavJustTabbedId = NavJustMovedToId = NavNextActivateId = 0;
    735       NavInputSource = ImGuiInputSource_None;
    736       NavScoringRectScreen = ImRect();
    737       NavScoringCount = 0;
    738       NavWindowingTarget = NULL;
    739       NavWindowingHighlightTimer = NavWindowingHighlightAlpha = 0.0f;
    740       NavWindowingToggleLayer = false;
    741       NavLayer = 0;
    742       NavIdTabCounter = INT_MAX;
    743       NavIdIsAlive = false;
    744       NavMousePosDirty = false;
    745       NavDisableHighlight = true;
    746       NavDisableMouseHover = false;
    747       NavAnyRequest = false;
    748       NavInitRequest = false;
    749       NavInitRequestFromMove = false;
    750       NavInitResultId = 0;
    751       NavMoveFromClampedRefRect = false;
    752       NavMoveRequest = false;
    753       NavMoveRequestForward = ImGuiNavForward_None;
    754       NavMoveDir = NavMoveDirLast = ImGuiDir_None;
    755 
    756       ModalWindowDarkeningRatio = 0.0f;
    757       OverlayDrawList._Data = &DrawListSharedData;
    758       OverlayDrawList._OwnerName = "##Overlay"; // Give it a name for debugging
    759       MouseCursor = ImGuiMouseCursor_Arrow;
    760 
    761       DragDropActive = false;
    762       DragDropSourceFlags = 0;
    763       DragDropMouseButton = -1;
    764       DragDropTargetId = 0;
    765       DragDropAcceptIdCurrRectSurface = 0.0f;
    766       DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0;
    767       DragDropAcceptFrameCount = -1;
    768       memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal));
    769 
    770       ScalarAsInputTextId = 0;
    771       ColorEditOptions = ImGuiColorEditFlags__OptionsDefault;
    772       DragCurrentValue = 0.0f;
    773       DragLastMouseDelta = ImVec2(0.0f, 0.0f);
    774       DragSpeedDefaultRatio = 1.0f / 100.0f;
    775       DragSpeedScaleSlow = 1.0f / 100.0f;
    776       DragSpeedScaleFast = 10.0f;
    777       ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f);
    778       TooltipOverrideCount = 0;
    779       PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX);
    780 
    781       SettingsLoaded = false;
    782       SettingsDirtyTimer = 0.0f;
    783 
    784       LogEnabled = false;
    785       LogFile = NULL;
    786       LogClipboard = NULL;
    787       LogStartDepth = 0;
    788       LogAutoExpandMaxDepth = 2;
    789 
    790       memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame));
    791       FramerateSecPerFrameIdx = 0;
    792       FramerateSecPerFrameAccum = 0.0f;
    793       WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1;
    794       memset(TempBuffer, 0, sizeof(TempBuffer));
    795    }
    796 };
     565    ImVector<ImDrawList*>   Layers[2];           // Global layers for: regular, tooltip
     566
     567    void Clear()            { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].resize(0); }
     568    void ClearFreeMemory()  { for (int n = 0; n < IM_ARRAYSIZE(Layers); n++) Layers[n].clear(); }
     569    IMGUI_API void FlattenIntoSingleLayer();
     570};
     571
     572//-----------------------------------------------------------------------------
     573// [SECTION] Widgets support: flags, enums, data structures
     574//-----------------------------------------------------------------------------
    797575
    798576// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin().
     
    800578enum ImGuiItemFlags_
    801579{
    802    ImGuiItemFlags_AllowKeyboardFocus = 1 << 0,  // true
    803    ImGuiItemFlags_ButtonRepeat = 1 << 1,  // false    // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
    804    ImGuiItemFlags_Disabled = 1 << 2,  // false    // FIXME-WIP: Disable interactions but doesn't affect visuals. Should be: grey out and disable interactions with widgets that affect data + view widgets (WIP)
    805    ImGuiItemFlags_NoNav = 1 << 3,  // false
    806    ImGuiItemFlags_NoNavDefaultFocus = 1 << 4,  // false
    807    ImGuiItemFlags_SelectableDontClosePopup = 1 << 5,  // false    // MenuItem/Selectable() automatically closes current Popup window
    808    ImGuiItemFlags_Default_ = ImGuiItemFlags_AllowKeyboardFocus
    809 };
    810 
    811 // Transient per-window data, reset at the beginning of the frame
    812 // FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiDrawContext is quite tenuous and could be reconsidered.
    813 struct IMGUI_API ImGuiDrawContext
    814 {
    815    ImVec2                  CursorPos;
    816    ImVec2                  CursorPosPrevLine;
    817    ImVec2                  CursorStartPos;
    818    ImVec2                  CursorMaxPos;           // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame
    819    float                   CurrentLineHeight;
    820    float                   CurrentLineTextBaseOffset;
    821    float                   PrevLineHeight;
    822    float                   PrevLineTextBaseOffset;
    823    float                   LogLinePosY;
    824    int                     TreeDepth;
    825    ImU32                   TreeDepthMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31
    826    ImGuiID                 LastItemId;
    827    ImGuiItemStatusFlags    LastItemStatusFlags;
    828    ImRect                  LastItemRect;           // Interaction rect
    829    ImRect                  LastItemDisplayRect;    // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
    830    bool                    NavHideHighlightOneFrame;
    831    bool                    NavHasScroll;           // Set when scrolling can be used (ScrollMax > 0.0f)
    832    int                     NavLayerCurrent;        // Current layer, 0..31 (we currently only use 0..1)
    833    int                     NavLayerCurrentMask;    // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping.
    834    int                     NavLayerActiveMask;     // Which layer have been written to (result from previous frame)
    835    int                     NavLayerActiveMaskNext; // Which layer have been written to (buffer for current frame)
    836    bool                    MenuBarAppending;       // FIXME: Remove this
    837    ImVec2                  MenuBarOffset;          // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.
    838    ImVector<ImGuiWindow*>  ChildWindows;
    839    ImGuiStorage*           StateStorage;
    840    ImGuiLayoutType         LayoutType;
    841    ImGuiLayoutType         ParentLayoutType;       // Layout type of parent window at the time of Begin()
    842 
    843                                                    // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
    844    ImGuiItemFlags          ItemFlags;              // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default]
    845    float                   ItemWidth;              // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window
    846    float                   TextWrapPos;            // == TextWrapPosStack.back() [empty == -1.0f]
    847    ImVector<ImGuiItemFlags>ItemFlagsStack;
    848    ImVector<float>         ItemWidthStack;
    849    ImVector<float>         TextWrapPosStack;
    850    ImVector<ImGuiGroupData>GroupStack;
    851    int                     StackSizesBackup[6];    // Store size of various stacks for asserting
    852 
    853    float                   IndentX;                // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
    854    float                   GroupOffsetX;
    855    float                   ColumnsOffsetX;         // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.
    856    ImGuiColumnsSet*        ColumnsSet;             // Current columns set
    857 
    858    ImGuiDrawContext()
    859    {
    860       CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f);
    861       CurrentLineHeight = PrevLineHeight = 0.0f;
    862       CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f;
    863       LogLinePosY = -1.0f;
    864       TreeDepth = 0;
    865       TreeDepthMayJumpToParentOnPop = 0x00;
    866       LastItemId = 0;
    867       LastItemStatusFlags = 0;
    868       LastItemRect = LastItemDisplayRect = ImRect();
    869       NavHideHighlightOneFrame = false;
    870       NavHasScroll = false;
    871       NavLayerActiveMask = NavLayerActiveMaskNext = 0x00;
    872       NavLayerCurrent = 0;
    873       NavLayerCurrentMask = 1 << 0;
    874       MenuBarAppending = false;
    875       MenuBarOffset = ImVec2(0.0f, 0.0f);
    876       StateStorage = NULL;
    877       LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical;
    878       ItemWidth = 0.0f;
    879       ItemFlags = ImGuiItemFlags_Default_;
    880       TextWrapPos = -1.0f;
    881       memset(StackSizesBackup, 0, sizeof(StackSizesBackup));
    882 
    883       IndentX = 0.0f;
    884       GroupOffsetX = 0.0f;
    885       ColumnsOffsetX = 0.0f;
    886       ColumnsSet = NULL;
    887    }
    888 };
    889 
    890 // Windows data
     580    ImGuiItemFlags_None                     = 0,
     581    ImGuiItemFlags_NoTabStop                = 1 << 0,  // false
     582    ImGuiItemFlags_ButtonRepeat             = 1 << 1,  // false    // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
     583    ImGuiItemFlags_Disabled                 = 1 << 2,  // false    // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
     584    ImGuiItemFlags_NoNav                    = 1 << 3,  // false
     585    ImGuiItemFlags_NoNavDefaultFocus        = 1 << 4,  // false
     586    ImGuiItemFlags_SelectableDontClosePopup = 1 << 5,  // false    // MenuItem/Selectable() automatically closes current Popup window
     587    ImGuiItemFlags_MixedValue               = 1 << 6,  // false    // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
     588    ImGuiItemFlags_ReadOnly                 = 1 << 7,  // false    // [ALPHA] Allow hovering interactions but underlying value is not changed.
     589    ImGuiItemFlags_Default_                 = 0
     590};
     591
     592// Storage for LastItem data
     593enum ImGuiItemStatusFlags_
     594{
     595    ImGuiItemStatusFlags_None               = 0,
     596    ImGuiItemStatusFlags_HoveredRect        = 1 << 0,
     597    ImGuiItemStatusFlags_HasDisplayRect     = 1 << 1,
     598    ImGuiItemStatusFlags_Edited             = 1 << 2,   // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)
     599    ImGuiItemStatusFlags_ToggledSelection   = 1 << 3,   // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues.
     600    ImGuiItemStatusFlags_ToggledOpen        = 1 << 4,   // Set when TreeNode() reports toggling their open state.
     601    ImGuiItemStatusFlags_HasDeactivated     = 1 << 5,   // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag.
     602    ImGuiItemStatusFlags_Deactivated        = 1 << 6    // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.
     603
     604#ifdef IMGUI_ENABLE_TEST_ENGINE
     605    , // [imgui_tests only]
     606    ImGuiItemStatusFlags_Openable           = 1 << 10,  //
     607    ImGuiItemStatusFlags_Opened             = 1 << 11,  //
     608    ImGuiItemStatusFlags_Checkable          = 1 << 12,  //
     609    ImGuiItemStatusFlags_Checked            = 1 << 13   //
     610#endif
     611};
     612
     613// Extend ImGuiButtonFlags_
     614enum ImGuiButtonFlagsPrivate_
     615{
     616    ImGuiButtonFlags_PressedOnClick         = 1 << 4,   // return true on click (mouse down event)
     617    ImGuiButtonFlags_PressedOnClickRelease  = 1 << 5,   // [Default] return true on click + release on same item <-- this is what the majority of Button are using
     618    ImGuiButtonFlags_PressedOnClickReleaseAnywhere = 1 << 6, // return true on click + release even if the release event is not done while hovering the item
     619    ImGuiButtonFlags_PressedOnRelease       = 1 << 7,   // return true on release (default requires click+release)
     620    ImGuiButtonFlags_PressedOnDoubleClick   = 1 << 8,   // return true on double-click (default requires click+release)
     621    ImGuiButtonFlags_PressedOnDragDropHold  = 1 << 9,   // return true when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers)
     622    ImGuiButtonFlags_Repeat                 = 1 << 10,  // hold to repeat
     623    ImGuiButtonFlags_FlattenChildren        = 1 << 11,  // allow interactions even if a child window is overlapping
     624    ImGuiButtonFlags_AllowItemOverlap       = 1 << 12,  // require previous frame HoveredId to either match id or be null before being usable, use along with SetItemAllowOverlap()
     625    ImGuiButtonFlags_DontClosePopups        = 1 << 13,  // disable automatically closing parent popup on press // [UNUSED]
     626    ImGuiButtonFlags_Disabled               = 1 << 14,  // disable interactions
     627    ImGuiButtonFlags_AlignTextBaseLine      = 1 << 15,  // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine
     628    ImGuiButtonFlags_NoKeyModifiers         = 1 << 16,  // disable mouse interaction if a key modifier is held
     629    ImGuiButtonFlags_NoHoldingActiveId      = 1 << 17,  // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only)
     630    ImGuiButtonFlags_NoNavFocus             = 1 << 18,  // don't override navigation focus when activated
     631    ImGuiButtonFlags_NoHoveredOnFocus       = 1 << 19,  // don't report as hovered when nav focus is on this item
     632    ImGuiButtonFlags_PressedOnMask_         = ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere | ImGuiButtonFlags_PressedOnRelease | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_PressedOnDragDropHold,
     633    ImGuiButtonFlags_PressedOnDefault_      = ImGuiButtonFlags_PressedOnClickRelease
     634};
     635
     636// Extend ImGuiSliderFlags_
     637enum ImGuiSliderFlagsPrivate_
     638{
     639    ImGuiSliderFlags_Vertical               = 1 << 20,  // Should this slider be orientated vertically?
     640    ImGuiSliderFlags_ReadOnly               = 1 << 21
     641};
     642
     643// Extend ImGuiSelectableFlags_
     644enum ImGuiSelectableFlagsPrivate_
     645{
     646    // NB: need to be in sync with last value of ImGuiSelectableFlags_
     647    ImGuiSelectableFlags_NoHoldingActiveID      = 1 << 20,
     648    ImGuiSelectableFlags_SelectOnClick          = 1 << 21,  // Override button behavior to react on Click (default is Click+Release)
     649    ImGuiSelectableFlags_SelectOnRelease        = 1 << 22,  // Override button behavior to react on Release (default is Click+Release)
     650    ImGuiSelectableFlags_SpanAvailWidth         = 1 << 23,  // Span all avail width even if we declared less for layout purpose. FIXME: We may be able to remove this (added in 6251d379, 2bcafc86 for menus)
     651    ImGuiSelectableFlags_DrawHoveredWhenHeld    = 1 << 24,  // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow.
     652    ImGuiSelectableFlags_SetNavIdOnHover        = 1 << 25,  // Set Nav/Focus ID on mouse hover (used by MenuItem)
     653    ImGuiSelectableFlags_NoPadWithHalfSpacing   = 1 << 26   // Disable padding each side with ItemSpacing * 0.5f
     654};
     655
     656// Extend ImGuiTreeNodeFlags_
     657enum ImGuiTreeNodeFlagsPrivate_
     658{
     659    ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20
     660};
     661
     662enum ImGuiSeparatorFlags_
     663{
     664    ImGuiSeparatorFlags_None                = 0,
     665    ImGuiSeparatorFlags_Horizontal          = 1 << 0,   // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar
     666    ImGuiSeparatorFlags_Vertical            = 1 << 1,
     667    ImGuiSeparatorFlags_SpanAllColumns      = 1 << 2
     668};
     669
     670enum ImGuiTextFlags_
     671{
     672    ImGuiTextFlags_None = 0,
     673    ImGuiTextFlags_NoWidthForLargeClippedText = 1 << 0
     674};
     675
     676enum ImGuiTooltipFlags_
     677{
     678    ImGuiTooltipFlags_None = 0,
     679    ImGuiTooltipFlags_OverridePreviousTooltip = 1 << 0      // Override will clear/ignore previously submitted tooltip (defaults to append)
     680};
     681
     682// FIXME: this is in development, not exposed/functional as a generic feature yet.
     683// Horizontal/Vertical enums are fixed to 0/1 so they may be used to index ImVec2
     684enum ImGuiLayoutType_
     685{
     686    ImGuiLayoutType_Horizontal = 0,
     687    ImGuiLayoutType_Vertical = 1
     688};
     689
     690enum ImGuiLogType
     691{
     692    ImGuiLogType_None = 0,
     693    ImGuiLogType_TTY,
     694    ImGuiLogType_File,
     695    ImGuiLogType_Buffer,
     696    ImGuiLogType_Clipboard
     697};
     698
     699// X/Y enums are fixed to 0/1 so they may be used to index ImVec2
     700enum ImGuiAxis
     701{
     702    ImGuiAxis_None = -1,
     703    ImGuiAxis_X = 0,
     704    ImGuiAxis_Y = 1
     705};
     706
     707enum ImGuiPlotType
     708{
     709    ImGuiPlotType_Lines,
     710    ImGuiPlotType_Histogram
     711};
     712
     713enum ImGuiInputSource
     714{
     715    ImGuiInputSource_None = 0,
     716    ImGuiInputSource_Mouse,
     717    ImGuiInputSource_Nav,
     718    ImGuiInputSource_NavKeyboard,   // Only used occasionally for storage, not tested/handled by most code
     719    ImGuiInputSource_NavGamepad,    // "
     720    ImGuiInputSource_COUNT
     721};
     722
     723// FIXME-NAV: Clarify/expose various repeat delay/rate
     724enum ImGuiInputReadMode
     725{
     726    ImGuiInputReadMode_Down,
     727    ImGuiInputReadMode_Pressed,
     728    ImGuiInputReadMode_Released,
     729    ImGuiInputReadMode_Repeat,
     730    ImGuiInputReadMode_RepeatSlow,
     731    ImGuiInputReadMode_RepeatFast
     732};
     733
     734enum ImGuiNavHighlightFlags_
     735{
     736    ImGuiNavHighlightFlags_None         = 0,
     737    ImGuiNavHighlightFlags_TypeDefault  = 1 << 0,
     738    ImGuiNavHighlightFlags_TypeThin     = 1 << 1,
     739    ImGuiNavHighlightFlags_AlwaysDraw   = 1 << 2,       // Draw rectangular highlight if (g.NavId == id) _even_ when using the mouse.
     740    ImGuiNavHighlightFlags_NoRounding   = 1 << 3
     741};
     742
     743enum ImGuiNavDirSourceFlags_
     744{
     745    ImGuiNavDirSourceFlags_None         = 0,
     746    ImGuiNavDirSourceFlags_Keyboard     = 1 << 0,
     747    ImGuiNavDirSourceFlags_PadDPad      = 1 << 1,
     748    ImGuiNavDirSourceFlags_PadLStick    = 1 << 2
     749};
     750
     751enum ImGuiNavMoveFlags_
     752{
     753    ImGuiNavMoveFlags_None                  = 0,
     754    ImGuiNavMoveFlags_LoopX                 = 1 << 0,   // On failed request, restart from opposite side
     755    ImGuiNavMoveFlags_LoopY                 = 1 << 1,
     756    ImGuiNavMoveFlags_WrapX                 = 1 << 2,   // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left)
     757    ImGuiNavMoveFlags_WrapY                 = 1 << 3,   // This is not super useful for provided for completeness
     758    ImGuiNavMoveFlags_AllowCurrentNavId     = 1 << 4,   // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place)
     759    ImGuiNavMoveFlags_AlsoScoreVisibleSet   = 1 << 5,   // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible.
     760    ImGuiNavMoveFlags_ScrollToEdge          = 1 << 6
     761};
     762
     763enum ImGuiNavForward
     764{
     765    ImGuiNavForward_None,
     766    ImGuiNavForward_ForwardQueued,
     767    ImGuiNavForward_ForwardActive
     768};
     769
     770enum ImGuiNavLayer
     771{
     772    ImGuiNavLayer_Main  = 0,    // Main scrolling layer
     773    ImGuiNavLayer_Menu  = 1,    // Menu layer (access with Alt/ImGuiNavInput_Menu)
     774    ImGuiNavLayer_COUNT
     775};
     776
     777enum ImGuiPopupPositionPolicy
     778{
     779    ImGuiPopupPositionPolicy_Default,
     780    ImGuiPopupPositionPolicy_ComboBox,
     781    ImGuiPopupPositionPolicy_Tooltip
     782};
     783
     784struct ImGuiDataTypeTempStorage
     785{
     786    ImU8        Data[8];        // Can fit any data up to ImGuiDataType_COUNT
     787};
     788
     789// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo().
     790struct ImGuiDataTypeInfo
     791{
     792    size_t      Size;           // Size in bytes
     793    const char* Name;           // Short descriptive name for the type, for debugging
     794    const char* PrintFmt;       // Default printf format for the type
     795    const char* ScanFmt;        // Default scanf format for the type
     796};
     797
     798// Extend ImGuiDataType_
     799enum ImGuiDataTypePrivate_
     800{
     801    ImGuiDataType_String = ImGuiDataType_COUNT + 1,
     802    ImGuiDataType_Pointer,
     803    ImGuiDataType_ID
     804};
     805
     806// Stacked color modifier, backup of modified data so we can restore it
     807struct ImGuiColorMod
     808{
     809    ImGuiCol    Col;
     810    ImVec4      BackupValue;
     811};
     812
     813// Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.
     814struct ImGuiStyleMod
     815{
     816    ImGuiStyleVar   VarIdx;
     817    union           { int BackupInt[2]; float BackupFloat[2]; };
     818    ImGuiStyleMod(ImGuiStyleVar idx, int v)     { VarIdx = idx; BackupInt[0] = v; }
     819    ImGuiStyleMod(ImGuiStyleVar idx, float v)   { VarIdx = idx; BackupFloat[0] = v; }
     820    ImGuiStyleMod(ImGuiStyleVar idx, ImVec2 v)  { VarIdx = idx; BackupFloat[0] = v.x; BackupFloat[1] = v.y; }
     821};
     822
     823// Stacked storage data for BeginGroup()/EndGroup()
     824struct ImGuiGroupData
     825{
     826    ImVec2      BackupCursorPos;
     827    ImVec2      BackupCursorMaxPos;
     828    ImVec1      BackupIndent;
     829    ImVec1      BackupGroupOffset;
     830    ImVec2      BackupCurrLineSize;
     831    float       BackupCurrLineTextBaseOffset;
     832    ImGuiID     BackupActiveIdIsAlive;
     833    bool        BackupActiveIdPreviousFrameIsAlive;
     834    bool        EmitItem;
     835};
     836
     837// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper.
     838struct IMGUI_API ImGuiMenuColumns
     839{
     840    float       Spacing;
     841    float       Width, NextWidth;
     842    float       Pos[3], NextWidths[3];
     843
     844    ImGuiMenuColumns();
     845    void        Update(int count, float spacing, bool clear);
     846    float       DeclColumns(float w0, float w1, float w2);
     847    float       CalcExtraSpace(float avail_w) const;
     848};
     849
     850// Internal state of the currently focused/edited text input box
     851// For a given item ID, access with ImGui::GetInputTextState()
     852struct IMGUI_API ImGuiInputTextState
     853{
     854    ImGuiID                 ID;                     // widget id owning the text state
     855    int                     CurLenW, CurLenA;       // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not.
     856    ImVector<ImWchar>       TextW;                  // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
     857    ImVector<char>          TextA;                  // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity.
     858    ImVector<char>          InitialTextA;           // backup of end-user buffer at the time of focus (in UTF-8, unaltered)
     859    bool                    TextAIsValid;           // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument)
     860    int                     BufCapacityA;           // end-user buffer capacity
     861    float                   ScrollX;                // horizontal scrolling/offset
     862    ImStb::STB_TexteditState Stb;                   // state for stb_textedit.h
     863    float                   CursorAnim;             // timer for cursor blink, reset on every user action so the cursor reappears immediately
     864    bool                    CursorFollow;           // set when we want scrolling to follow the current cursor position (not always!)
     865    bool                    SelectedAllMouseLock;   // after a double-click to select all, we ignore further mouse drags to update selection
     866    bool                    Edited;                 // edited this frame
     867    ImGuiInputTextFlags     UserFlags;              // Temporarily set while we call user's callback
     868    ImGuiInputTextCallback  UserCallback;           // "
     869    void*                   UserCallbackData;       // "
     870
     871    ImGuiInputTextState()                   { memset(this, 0, sizeof(*this)); }
     872    void        ClearText()                 { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); }
     873    void        ClearFreeMemory()           { TextW.clear(); TextA.clear(); InitialTextA.clear(); }
     874    int         GetUndoAvailCount() const   { return Stb.undostate.undo_point; }
     875    int         GetRedoAvailCount() const   { return STB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; }
     876    void        OnKeyPressed(int key);      // Cannot be inline because we call in code in stb_textedit.h implementation
     877
     878    // Cursor & Selection
     879    void        CursorAnimReset()           { CursorAnim = -0.30f; }                                   // After a user-input the cursor stays on for a while without blinking
     880    void        CursorClamp()               { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); }
     881    bool        HasSelection() const        { return Stb.select_start != Stb.select_end; }
     882    void        ClearSelection()            { Stb.select_start = Stb.select_end = Stb.cursor; }
     883    void        SelectAll()                 { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; }
     884};
     885
     886// Storage for current popup stack
     887struct ImGuiPopupData
     888{
     889    ImGuiID             PopupId;        // Set on OpenPopup()
     890    ImGuiWindow*        Window;         // Resolved on BeginPopup() - may stay unresolved if user never calls OpenPopup()
     891    ImGuiWindow*        SourceWindow;   // Set on OpenPopup() copy of NavWindow at the time of opening the popup
     892    int                 OpenFrameCount; // Set on OpenPopup()
     893    ImGuiID             OpenParentId;   // Set on OpenPopup(), we need this to differentiate multiple menu sets from each others (e.g. inside menu bar vs loose menu items)
     894    ImVec2              OpenPopupPos;   // Set on OpenPopup(), preferred popup position (typically == OpenMousePos when using mouse)
     895    ImVec2              OpenMousePos;   // Set on OpenPopup(), copy of mouse position at the time of opening popup
     896
     897    ImGuiPopupData() { PopupId = 0; Window = SourceWindow = NULL; OpenFrameCount = -1; OpenParentId = 0; }
     898};
     899
     900struct ImGuiNavMoveResult
     901{
     902    ImGuiWindow*    Window;             // Best candidate window
     903    ImGuiID         ID;                 // Best candidate ID
     904    ImGuiID         FocusScopeId;       // Best candidate focus scope ID
     905    float           DistBox;            // Best candidate box distance to current NavId
     906    float           DistCenter;         // Best candidate center distance to current NavId
     907    float           DistAxial;
     908    ImRect          RectRel;            // Best candidate bounding box in window relative space
     909
     910    ImGuiNavMoveResult() { Clear(); }
     911    void Clear()         { Window = NULL; ID = FocusScopeId = 0; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); }
     912};
     913
     914enum ImGuiNextWindowDataFlags_
     915{
     916    ImGuiNextWindowDataFlags_None               = 0,
     917    ImGuiNextWindowDataFlags_HasPos             = 1 << 0,
     918    ImGuiNextWindowDataFlags_HasSize            = 1 << 1,
     919    ImGuiNextWindowDataFlags_HasContentSize     = 1 << 2,
     920    ImGuiNextWindowDataFlags_HasCollapsed       = 1 << 3,
     921    ImGuiNextWindowDataFlags_HasSizeConstraint  = 1 << 4,
     922    ImGuiNextWindowDataFlags_HasFocus           = 1 << 5,
     923    ImGuiNextWindowDataFlags_HasBgAlpha         = 1 << 6,
     924    ImGuiNextWindowDataFlags_HasScroll          = 1 << 7
     925};
     926
     927// Storage for SetNexWindow** functions
     928struct ImGuiNextWindowData
     929{
     930    ImGuiNextWindowDataFlags    Flags;
     931    ImGuiCond                   PosCond;
     932    ImGuiCond                   SizeCond;
     933    ImGuiCond                   CollapsedCond;
     934    ImVec2                      PosVal;
     935    ImVec2                      PosPivotVal;
     936    ImVec2                      SizeVal;
     937    ImVec2                      ContentSizeVal;
     938    ImVec2                      ScrollVal;
     939    bool                        CollapsedVal;
     940    ImRect                      SizeConstraintRect;
     941    ImGuiSizeCallback           SizeCallback;
     942    void*                       SizeCallbackUserData;
     943    float                       BgAlphaVal;             // Override background alpha
     944    ImVec2                      MenuBarOffsetMinVal;    // *Always on* This is not exposed publicly, so we don't clear it.
     945
     946    ImGuiNextWindowData()       { memset(this, 0, sizeof(*this)); }
     947    inline void ClearFlags()    { Flags = ImGuiNextWindowDataFlags_None; }
     948};
     949
     950enum ImGuiNextItemDataFlags_
     951{
     952    ImGuiNextItemDataFlags_None     = 0,
     953    ImGuiNextItemDataFlags_HasWidth = 1 << 0,
     954    ImGuiNextItemDataFlags_HasOpen  = 1 << 1
     955};
     956
     957struct ImGuiNextItemData
     958{
     959    ImGuiNextItemDataFlags      Flags;
     960    float                       Width;          // Set by SetNextItemWidth()
     961    ImGuiID                     FocusScopeId;   // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging)
     962    ImGuiCond                   OpenCond;
     963    bool                        OpenVal;        // Set by SetNextItemOpen()
     964
     965    ImGuiNextItemData()         { memset(this, 0, sizeof(*this)); }
     966    inline void ClearFlags()    { Flags = ImGuiNextItemDataFlags_None; } // Also cleared manually by ItemAdd()!
     967};
     968
     969struct ImGuiShrinkWidthItem
     970{
     971    int         Index;
     972    float       Width;
     973};
     974
     975struct ImGuiPtrOrIndex
     976{
     977    void*       Ptr;            // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool.
     978    int         Index;          // Usually index in a main pool.
     979
     980    ImGuiPtrOrIndex(void* ptr)  { Ptr = ptr; Index = -1; }
     981    ImGuiPtrOrIndex(int index)  { Ptr = NULL; Index = index; }
     982};
     983
     984//-----------------------------------------------------------------------------
     985// [SECTION] Columns support
     986//-----------------------------------------------------------------------------
     987
     988enum ImGuiColumnsFlags_
     989{
     990    // Default: 0
     991    ImGuiColumnsFlags_None                  = 0,
     992    ImGuiColumnsFlags_NoBorder              = 1 << 0,   // Disable column dividers
     993    ImGuiColumnsFlags_NoResize              = 1 << 1,   // Disable resizing columns when clicking on the dividers
     994    ImGuiColumnsFlags_NoPreserveWidths      = 1 << 2,   // Disable column width preservation when adjusting columns
     995    ImGuiColumnsFlags_NoForceWithinWindow   = 1 << 3,   // Disable forcing columns to fit within window
     996    ImGuiColumnsFlags_GrowParentContentsSize= 1 << 4    // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove.
     997};
     998
     999struct ImGuiColumnData
     1000{
     1001    float               OffsetNorm;         // Column start offset, normalized 0.0 (far left) -> 1.0 (far right)
     1002    float               OffsetNormBeforeResize;
     1003    ImGuiColumnsFlags   Flags;              // Not exposed
     1004    ImRect              ClipRect;
     1005
     1006    ImGuiColumnData()   { OffsetNorm = OffsetNormBeforeResize = 0.0f; Flags = ImGuiColumnsFlags_None; }
     1007};
     1008
     1009struct ImGuiColumns
     1010{
     1011    ImGuiID             ID;
     1012    ImGuiColumnsFlags   Flags;
     1013    bool                IsFirstFrame;
     1014    bool                IsBeingResized;
     1015    int                 Current;
     1016    int                 Count;
     1017    float               OffMinX, OffMaxX;       // Offsets from HostWorkRect.Min.x
     1018    float               LineMinY, LineMaxY;
     1019    float               HostCursorPosY;         // Backup of CursorPos at the time of BeginColumns()
     1020    float               HostCursorMaxPosX;      // Backup of CursorMaxPos at the time of BeginColumns()
     1021    ImRect              HostInitialClipRect;    // Backup of ClipRect at the time of BeginColumns()
     1022    ImRect              HostBackupClipRect;     // Backup of ClipRect during PushColumnsBackground()/PopColumnsBackground()
     1023    ImRect              HostBackupParentWorkRect;//Backup of WorkRect at the time of BeginColumns()
     1024    ImVector<ImGuiColumnData> Columns;
     1025    ImDrawListSplitter  Splitter;
     1026
     1027    ImGuiColumns()      { Clear(); }
     1028    void Clear()
     1029    {
     1030        ID = 0;
     1031        Flags = ImGuiColumnsFlags_None;
     1032        IsFirstFrame = false;
     1033        IsBeingResized = false;
     1034        Current = 0;
     1035        Count = 1;
     1036        OffMinX = OffMaxX = 0.0f;
     1037        LineMinY = LineMaxY = 0.0f;
     1038        HostCursorPosY = 0.0f;
     1039        HostCursorMaxPosX = 0.0f;
     1040        Columns.clear();
     1041    }
     1042};
     1043
     1044//-----------------------------------------------------------------------------
     1045// [SECTION] Multi-select support
     1046//-----------------------------------------------------------------------------
     1047
     1048#ifdef IMGUI_HAS_MULTI_SELECT
     1049// <this is filled in 'range_select' branch>
     1050#endif // #ifdef IMGUI_HAS_MULTI_SELECT
     1051
     1052//-----------------------------------------------------------------------------
     1053// [SECTION] Docking support
     1054//-----------------------------------------------------------------------------
     1055
     1056#ifdef IMGUI_HAS_DOCK
     1057// <this is filled in 'docking' branch>
     1058#endif // #ifdef IMGUI_HAS_DOCK
     1059
     1060//-----------------------------------------------------------------------------
     1061// [SECTION] Viewport support
     1062//-----------------------------------------------------------------------------
     1063
     1064#ifdef IMGUI_HAS_VIEWPORT
     1065// <this is filled in 'docking' branch>
     1066#endif // #ifdef IMGUI_HAS_VIEWPORT
     1067
     1068//-----------------------------------------------------------------------------
     1069// [SECTION] Settings support
     1070//-----------------------------------------------------------------------------
     1071
     1072// Windows data saved in imgui.ini file
     1073// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily.
     1074// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure)
     1075struct ImGuiWindowSettings
     1076{
     1077    ImGuiID     ID;
     1078    ImVec2ih    Pos;
     1079    ImVec2ih    Size;
     1080    bool        Collapsed;
     1081    bool        WantApply;      // Set when loaded from .ini data (to enable merging/loading .ini data into an already running context)
     1082
     1083    ImGuiWindowSettings()       { ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = WantApply = false; }
     1084    char* GetName()             { return (char*)(this + 1); }
     1085};
     1086
     1087struct ImGuiSettingsHandler
     1088{
     1089    const char* TypeName;       // Short description stored in .ini file. Disallowed characters: '[' ']'
     1090    ImGuiID     TypeHash;       // == ImHashStr(TypeName)
     1091    void        (*ClearAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler);                                // Clear all settings data
     1092    void        (*ReadInitFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler);                                // Read: Called before reading (in registration order)
     1093    void*       (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name);              // Read: Called when entering into a new ini entry e.g. "[Window][Name]"
     1094    void        (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry
     1095    void        (*ApplyAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler);                                // Read: Called after reading (in registration order)
     1096    void        (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf);      // Write: Output every entries into 'out_buf'
     1097    void*       UserData;
     1098
     1099    ImGuiSettingsHandler() { memset(this, 0, sizeof(*this)); }
     1100};
     1101
     1102//-----------------------------------------------------------------------------
     1103// [SECTION] ImGuiContext (main imgui context)
     1104//-----------------------------------------------------------------------------
     1105
     1106struct ImGuiContext
     1107{
     1108    bool                    Initialized;
     1109    bool                    FontAtlasOwnedByContext;            // IO.Fonts-> is owned by the ImGuiContext and will be destructed along with it.
     1110    ImGuiIO                 IO;
     1111    ImGuiStyle              Style;
     1112    ImFont*                 Font;                               // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()
     1113    float                   FontSize;                           // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
     1114    float                   FontBaseSize;                       // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
     1115    ImDrawListSharedData    DrawListSharedData;
     1116    double                  Time;
     1117    int                     FrameCount;
     1118    int                     FrameCountEnded;
     1119    int                     FrameCountRendered;
     1120    bool                    WithinFrameScope;                   // Set by NewFrame(), cleared by EndFrame()
     1121    bool                    WithinFrameScopeWithImplicitWindow; // Set by NewFrame(), cleared by EndFrame() when the implicit debug window has been pushed
     1122    bool                    WithinEndChild;                     // Set within EndChild()
     1123    bool                    TestEngineHookItems;                // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log()
     1124    ImGuiID                 TestEngineHookIdInfo;               // Will call test engine hooks: ImGuiTestEngineHook_IdInfo() from GetID()
     1125    void*                   TestEngine;                         // Test engine user data
     1126
     1127    // Windows state
     1128    ImVector<ImGuiWindow*>  Windows;                            // Windows, sorted in display order, back to front
     1129    ImVector<ImGuiWindow*>  WindowsFocusOrder;                  // Windows, sorted in focus order, back to front. (FIXME: We could only store root windows here! Need to sort out the Docking equivalent which is RootWindowDockStop and is unfortunately a little more dynamic)
     1130    ImVector<ImGuiWindow*>  WindowsTempSortBuffer;              // Temporary buffer used in EndFrame() to reorder windows so parents are kept before their child
     1131    ImVector<ImGuiWindow*>  CurrentWindowStack;
     1132    ImGuiStorage            WindowsById;                        // Map window's ImGuiID to ImGuiWindow*
     1133    int                     WindowsActiveCount;                 // Number of unique windows submitted by frame
     1134    ImGuiWindow*            CurrentWindow;                      // Window being drawn into
     1135    ImGuiWindow*            HoveredWindow;                      // Window the mouse is hovering. Will typically catch mouse inputs.
     1136    ImGuiWindow*            HoveredRootWindow;                  // == HoveredWindow ? HoveredWindow->RootWindow : NULL, merely a shortcut to avoid null test in some situation.
     1137    ImGuiWindow*            HoveredWindowUnderMovingWindow;     // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
     1138    ImGuiWindow*            MovingWindow;                       // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindow.
     1139    ImGuiWindow*            WheelingWindow;                     // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.
     1140    ImVec2                  WheelingWindowRefMousePos;
     1141    float                   WheelingWindowTimer;
     1142
     1143    // Item/widgets state and tracking information
     1144    ImGuiID                 HoveredId;                          // Hovered widget
     1145    ImGuiID                 HoveredIdPreviousFrame;
     1146    bool                    HoveredIdAllowOverlap;
     1147    bool                    HoveredIdDisabled;                  // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.
     1148    float                   HoveredIdTimer;                     // Measure contiguous hovering time
     1149    float                   HoveredIdNotActiveTimer;            // Measure contiguous hovering time where the item has not been active
     1150    ImGuiID                 ActiveId;                           // Active widget
     1151    ImGuiID                 ActiveIdIsAlive;                    // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)
     1152    float                   ActiveIdTimer;
     1153    bool                    ActiveIdIsJustActivated;            // Set at the time of activation for one frame
     1154    bool                    ActiveIdAllowOverlap;               // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always)
     1155    bool                    ActiveIdNoClearOnFocusLoss;         // Disable losing active id if the active id window gets unfocused.
     1156    bool                    ActiveIdHasBeenPressedBefore;       // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch.
     1157    bool                    ActiveIdHasBeenEditedBefore;        // Was the value associated to the widget Edited over the course of the Active state.
     1158    bool                    ActiveIdHasBeenEditedThisFrame;
     1159    ImU32                   ActiveIdUsingNavDirMask;            // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it)
     1160    ImU32                   ActiveIdUsingNavInputMask;          // Active widget will want to read those nav inputs.
     1161    ImU64                   ActiveIdUsingKeyInputMask;          // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array.
     1162    ImVec2                  ActiveIdClickOffset;                // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)
     1163    ImGuiWindow*            ActiveIdWindow;
     1164    ImGuiInputSource        ActiveIdSource;                     // Activating with mouse or nav (gamepad/keyboard)
     1165    int                     ActiveIdMouseButton;
     1166    ImGuiID                 ActiveIdPreviousFrame;
     1167    bool                    ActiveIdPreviousFrameIsAlive;
     1168    bool                    ActiveIdPreviousFrameHasBeenEditedBefore;
     1169    ImGuiWindow*            ActiveIdPreviousFrameWindow;
     1170    ImGuiID                 LastActiveId;                       // Store the last non-zero ActiveId, useful for animation.
     1171    float                   LastActiveIdTimer;                  // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
     1172
     1173    // Next window/item data
     1174    ImGuiNextWindowData     NextWindowData;                     // Storage for SetNextWindow** functions
     1175    ImGuiNextItemData       NextItemData;                       // Storage for SetNextItem** functions
     1176
     1177    // Shared stacks
     1178    ImVector<ImGuiColorMod> ColorModifiers;                     // Stack for PushStyleColor()/PopStyleColor()
     1179    ImVector<ImGuiStyleMod> StyleModifiers;                     // Stack for PushStyleVar()/PopStyleVar()
     1180    ImVector<ImFont*>       FontStack;                          // Stack for PushFont()/PopFont()
     1181    ImVector<ImGuiPopupData>OpenPopupStack;                     // Which popups are open (persistent)
     1182    ImVector<ImGuiPopupData>BeginPopupStack;                    // Which level of BeginPopup() we are in (reset every frame)
     1183
     1184    // Gamepad/keyboard Navigation
     1185    ImGuiWindow*            NavWindow;                          // Focused window for navigation. Could be called 'FocusWindow'
     1186    ImGuiID                 NavId;                              // Focused item for navigation
     1187    ImGuiID                 NavFocusScopeId;                    // Identify a selection scope (selection code often wants to "clear other items" when landing on an item of the selection set)
     1188    ImGuiID                 NavActivateId;                      // ~~ (g.ActiveId == 0) && IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0, also set when calling ActivateItem()
     1189    ImGuiID                 NavActivateDownId;                  // ~~ IsNavInputDown(ImGuiNavInput_Activate) ? NavId : 0
     1190    ImGuiID                 NavActivatePressedId;               // ~~ IsNavInputPressed(ImGuiNavInput_Activate) ? NavId : 0
     1191    ImGuiID                 NavInputId;                         // ~~ IsNavInputPressed(ImGuiNavInput_Input) ? NavId : 0
     1192    ImGuiID                 NavJustTabbedId;                    // Just tabbed to this id.
     1193    ImGuiID                 NavJustMovedToId;                   // Just navigated to this id (result of a successfully MoveRequest).
     1194    ImGuiID                 NavJustMovedToFocusScopeId;         // Just navigated to this focus scope id (result of a successfully MoveRequest).
     1195    ImGuiKeyModFlags        NavJustMovedToKeyMods;
     1196    ImGuiID                 NavNextActivateId;                  // Set by ActivateItem(), queued until next frame.
     1197    ImGuiInputSource        NavInputSource;                     // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard.
     1198    ImRect                  NavScoringRect;                     // Rectangle used for scoring, in screen space. Based of window->NavRectRel[], modified for directional navigation scoring.
     1199    int                     NavScoringCount;                    // Metrics for debugging
     1200    ImGuiNavLayer           NavLayer;                           // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
     1201    int                     NavIdTabCounter;                    // == NavWindow->DC.FocusIdxTabCounter at time of NavId processing
     1202    bool                    NavIdIsAlive;                       // Nav widget has been seen this frame ~~ NavRectRel is valid
     1203    bool                    NavMousePosDirty;                   // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
     1204    bool                    NavDisableHighlight;                // When user starts using mouse, we hide gamepad/keyboard highlight (NB: but they are still available, which is why NavDisableHighlight isn't always != NavDisableMouseHover)
     1205    bool                    NavDisableMouseHover;               // When user starts using gamepad/keyboard, we hide mouse hovering highlight until mouse is touched again.
     1206    bool                    NavAnyRequest;                      // ~~ NavMoveRequest || NavInitRequest
     1207    bool                    NavInitRequest;                     // Init request for appearing window to select first item
     1208    bool                    NavInitRequestFromMove;
     1209    ImGuiID                 NavInitResultId;                    // Init request result (first item of the window, or one for which SetItemDefaultFocus() was called)
     1210    ImRect                  NavInitResultRectRel;               // Init request result rectangle (relative to parent window)
     1211    bool                    NavMoveRequest;                     // Move request for this frame
     1212    ImGuiNavMoveFlags       NavMoveRequestFlags;
     1213    ImGuiNavForward         NavMoveRequestForward;              // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu)
     1214    ImGuiKeyModFlags        NavMoveRequestKeyMods;
     1215    ImGuiDir                NavMoveDir, NavMoveDirLast;         // Direction of the move request (left/right/up/down), direction of the previous move request
     1216    ImGuiDir                NavMoveClipDir;                     // FIXME-NAV: Describe the purpose of this better. Might want to rename?
     1217    ImGuiNavMoveResult      NavMoveResultLocal;                 // Best move request candidate within NavWindow
     1218    ImGuiNavMoveResult      NavMoveResultLocalVisibleSet;       // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag)
     1219    ImGuiNavMoveResult      NavMoveResultOther;                 // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
     1220    ImGuiWindow*            NavWrapRequestWindow;               // Window which requested trying nav wrap-around.
     1221    ImGuiNavMoveFlags       NavWrapRequestFlags;                // Wrap-around operation flags.
     1222
     1223    // Navigation: Windowing (CTRL+TAB for list, or Menu button + keys or directional pads to move/resize)
     1224    ImGuiWindow*            NavWindowingTarget;                 // Target window when doing CTRL+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most!
     1225    ImGuiWindow*            NavWindowingTargetAnim;             // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f, so the fade-out can stay on it.
     1226    ImGuiWindow*            NavWindowingListWindow;             // Internal window actually listing the CTRL+Tab contents
     1227    float                   NavWindowingTimer;
     1228    float                   NavWindowingHighlightAlpha;
     1229    bool                    NavWindowingToggleLayer;
     1230
     1231    // Legacy Focus/Tabbing system (older than Nav, active even if Nav is disabled, misnamed. FIXME-NAV: This needs a redesign!)
     1232    ImGuiWindow*            FocusRequestCurrWindow;             //
     1233    ImGuiWindow*            FocusRequestNextWindow;             //
     1234    int                     FocusRequestCurrCounterRegular;     // Any item being requested for focus, stored as an index (we on layout to be stable between the frame pressing TAB and the next frame, semi-ouch)
     1235    int                     FocusRequestCurrCounterTabStop;     // Tab item being requested for focus, stored as an index
     1236    int                     FocusRequestNextCounterRegular;     // Stored for next frame
     1237    int                     FocusRequestNextCounterTabStop;     // "
     1238    bool                    FocusTabPressed;                    //
     1239
     1240    // Render
     1241    ImDrawData              DrawData;                           // Main ImDrawData instance to pass render information to the user
     1242    ImDrawDataBuilder       DrawDataBuilder;
     1243    float                   DimBgRatio;                         // 0.0..1.0 animation when fading in a dimming background (for modal window and CTRL+TAB list)
     1244    ImDrawList              BackgroundDrawList;                 // First draw list to be rendered.
     1245    ImDrawList              ForegroundDrawList;                 // Last draw list to be rendered. This is where we the render software mouse cursor (if io.MouseDrawCursor is set) and most debug overlays.
     1246    ImGuiMouseCursor        MouseCursor;
     1247
     1248    // Drag and Drop
     1249    bool                    DragDropActive;
     1250    bool                    DragDropWithinSource;               // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag source.
     1251    bool                    DragDropWithinTarget;               // Set when within a BeginDragDropXXX/EndDragDropXXX block for a drag target.
     1252    ImGuiDragDropFlags      DragDropSourceFlags;
     1253    int                     DragDropSourceFrameCount;
     1254    int                     DragDropMouseButton;
     1255    ImGuiPayload            DragDropPayload;
     1256    ImRect                  DragDropTargetRect;                 // Store rectangle of current target candidate (we favor small targets when overlapping)
     1257    ImGuiID                 DragDropTargetId;
     1258    ImGuiDragDropFlags      DragDropAcceptFlags;
     1259    float                   DragDropAcceptIdCurrRectSurface;    // Target item surface (we resolve overlapping targets by prioritizing the smaller surface)
     1260    ImGuiID                 DragDropAcceptIdCurr;               // Target item id (set at the time of accepting the payload)
     1261    ImGuiID                 DragDropAcceptIdPrev;               // Target item id from previous frame (we need to store this to allow for overlapping drag and drop targets)
     1262    int                     DragDropAcceptFrameCount;           // Last time a target expressed a desire to accept the source
     1263    ImGuiID                 DragDropHoldJustPressedId;          // Set when holding a payload just made ButtonBehavior() return a press.
     1264    ImVector<unsigned char> DragDropPayloadBufHeap;             // We don't expose the ImVector<> directly, ImGuiPayload only holds pointer+size
     1265    unsigned char           DragDropPayloadBufLocal[16];        // Local buffer for small payloads
     1266
     1267    // Tab bars
     1268    ImGuiTabBar*                    CurrentTabBar;
     1269    ImPool<ImGuiTabBar>             TabBars;
     1270    ImVector<ImGuiPtrOrIndex>       CurrentTabBarStack;
     1271    ImVector<ImGuiShrinkWidthItem>  ShrinkWidthBuffer;
     1272
     1273    // Widget state
     1274    ImVec2                  LastValidMousePos;
     1275    ImGuiInputTextState     InputTextState;
     1276    ImFont                  InputTextPasswordFont;
     1277    ImGuiID                 TempInputId;                        // Temporary text input when CTRL+clicking on a slider, etc.
     1278    ImGuiColorEditFlags     ColorEditOptions;                   // Store user options for color edit widgets
     1279    float                   ColorEditLastHue;                   // Backup of last Hue associated to LastColor[3], so we can restore Hue in lossy RGB<>HSV round trips
     1280    float                   ColorEditLastSat;                   // Backup of last Saturation associated to LastColor[3], so we can restore Saturation in lossy RGB<>HSV round trips
     1281    float                   ColorEditLastColor[3];
     1282    ImVec4                  ColorPickerRef;                     // Initial/reference color at the time of opening the color picker.
     1283    float                   SliderCurrentAccum;                 // Accumulated slider delta when using navigation controls.
     1284    bool                    SliderCurrentAccumDirty;            // Has the accumulated slider delta changed since last time we tried to apply it?
     1285    bool                    DragCurrentAccumDirty;
     1286    float                   DragCurrentAccum;                   // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings
     1287    float                   DragSpeedDefaultRatio;              // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio
     1288    float                   ScrollbarClickDeltaToGrabCenter;    // Distance between mouse and center of grab box, normalized in parent space. Use storage?
     1289    int                     TooltipOverrideCount;
     1290    ImVector<char>          ClipboardHandlerData;               // If no custom clipboard handler is defined
     1291    ImVector<ImGuiID>       MenusIdSubmittedThisFrame;          // A list of menu IDs that were rendered at least once
     1292
     1293    // Platform support
     1294    ImVec2                  PlatformImePos;                     // Cursor position request & last passed to the OS Input Method Editor
     1295    ImVec2                  PlatformImeLastPos;
     1296    char                    PlatformLocaleDecimalPoint;         // '.' or *localeconv()->decimal_point
     1297
     1298    // Settings
     1299    bool                    SettingsLoaded;
     1300    float                   SettingsDirtyTimer;                 // Save .ini Settings to memory when time reaches zero
     1301    ImGuiTextBuffer         SettingsIniData;                    // In memory .ini settings
     1302    ImVector<ImGuiSettingsHandler>      SettingsHandlers;       // List of .ini settings handlers
     1303    ImChunkStream<ImGuiWindowSettings>  SettingsWindows;        // ImGuiWindow .ini settings entries
     1304
     1305    // Capture/Logging
     1306    bool                    LogEnabled;                         // Currently capturing
     1307    ImGuiLogType            LogType;                            // Capture target
     1308    ImFileHandle            LogFile;                            // If != NULL log to stdout/ file
     1309    ImGuiTextBuffer         LogBuffer;                          // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators.
     1310    float                   LogLinePosY;
     1311    bool                    LogLineFirstItem;
     1312    int                     LogDepthRef;
     1313    int                     LogDepthToExpand;
     1314    int                     LogDepthToExpandDefault;            // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call.
     1315
     1316    // Debug Tools
     1317    bool                    DebugItemPickerActive;              // Item picker is active (started with DebugStartItemPicker())
     1318    ImGuiID                 DebugItemPickerBreakId;             // Will call IM_DEBUG_BREAK() when encountering this id
     1319
     1320    // Misc
     1321    float                   FramerateSecPerFrame[120];          // Calculate estimate of framerate for user over the last 2 seconds.
     1322    int                     FramerateSecPerFrameIdx;
     1323    float                   FramerateSecPerFrameAccum;
     1324    int                     WantCaptureMouseNextFrame;          // Explicit capture via CaptureKeyboardFromApp()/CaptureMouseFromApp() sets those flags
     1325    int                     WantCaptureKeyboardNextFrame;
     1326    int                     WantTextInputNextFrame;
     1327    char                    TempBuffer[1024 * 3 + 1];           // Temporary text buffer
     1328
     1329    ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData)
     1330    {
     1331        Initialized = false;
     1332        FontAtlasOwnedByContext = shared_font_atlas ? false : true;
     1333        Font = NULL;
     1334        FontSize = FontBaseSize = 0.0f;
     1335        IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
     1336        Time = 0.0f;
     1337        FrameCount = 0;
     1338        FrameCountEnded = FrameCountRendered = -1;
     1339        WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false;
     1340        TestEngineHookItems = false;
     1341        TestEngineHookIdInfo = 0;
     1342        TestEngine = NULL;
     1343
     1344        WindowsActiveCount = 0;
     1345        CurrentWindow = NULL;
     1346        HoveredWindow = NULL;
     1347        HoveredRootWindow = NULL;
     1348        HoveredWindowUnderMovingWindow = NULL;
     1349        MovingWindow = NULL;
     1350        WheelingWindow = NULL;
     1351        WheelingWindowTimer = 0.0f;
     1352
     1353        HoveredId = HoveredIdPreviousFrame = 0;
     1354        HoveredIdAllowOverlap = false;
     1355        HoveredIdDisabled = false;
     1356        HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
     1357        ActiveId = 0;
     1358        ActiveIdIsAlive = 0;
     1359        ActiveIdTimer = 0.0f;
     1360        ActiveIdIsJustActivated = false;
     1361        ActiveIdAllowOverlap = false;
     1362        ActiveIdNoClearOnFocusLoss = false;
     1363        ActiveIdHasBeenPressedBefore = false;
     1364        ActiveIdHasBeenEditedBefore = false;
     1365        ActiveIdHasBeenEditedThisFrame = false;
     1366        ActiveIdUsingNavDirMask = 0x00;
     1367        ActiveIdUsingNavInputMask = 0x00;
     1368        ActiveIdUsingKeyInputMask = 0x00;
     1369        ActiveIdClickOffset = ImVec2(-1, -1);
     1370        ActiveIdWindow = NULL;
     1371        ActiveIdSource = ImGuiInputSource_None;
     1372        ActiveIdMouseButton = 0;
     1373        ActiveIdPreviousFrame = 0;
     1374        ActiveIdPreviousFrameIsAlive = false;
     1375        ActiveIdPreviousFrameHasBeenEditedBefore = false;
     1376        ActiveIdPreviousFrameWindow = NULL;
     1377        LastActiveId = 0;
     1378        LastActiveIdTimer = 0.0f;
     1379
     1380        NavWindow = NULL;
     1381        NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0;
     1382        NavJustTabbedId = NavJustMovedToId = NavJustMovedToFocusScopeId = NavNextActivateId = 0;
     1383        NavJustMovedToKeyMods = ImGuiKeyModFlags_None;
     1384        NavInputSource = ImGuiInputSource_None;
     1385        NavScoringRect = ImRect();
     1386        NavScoringCount = 0;
     1387        NavLayer = ImGuiNavLayer_Main;
     1388        NavIdTabCounter = INT_MAX;
     1389        NavIdIsAlive = false;
     1390        NavMousePosDirty = false;
     1391        NavDisableHighlight = true;
     1392        NavDisableMouseHover = false;
     1393        NavAnyRequest = false;
     1394        NavInitRequest = false;
     1395        NavInitRequestFromMove = false;
     1396        NavInitResultId = 0;
     1397        NavMoveRequest = false;
     1398        NavMoveRequestFlags = ImGuiNavMoveFlags_None;
     1399        NavMoveRequestForward = ImGuiNavForward_None;
     1400        NavMoveRequestKeyMods = ImGuiKeyModFlags_None;
     1401        NavMoveDir = NavMoveDirLast = NavMoveClipDir = ImGuiDir_None;
     1402        NavWrapRequestWindow = NULL;
     1403        NavWrapRequestFlags = ImGuiNavMoveFlags_None;
     1404
     1405        NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL;
     1406        NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f;
     1407        NavWindowingToggleLayer = false;
     1408
     1409        FocusRequestCurrWindow = FocusRequestNextWindow = NULL;
     1410        FocusRequestCurrCounterRegular = FocusRequestCurrCounterTabStop = INT_MAX;
     1411        FocusRequestNextCounterRegular = FocusRequestNextCounterTabStop = INT_MAX;
     1412        FocusTabPressed = false;
     1413
     1414        DimBgRatio = 0.0f;
     1415        BackgroundDrawList._OwnerName = "##Background"; // Give it a name for debugging
     1416        ForegroundDrawList._OwnerName = "##Foreground"; // Give it a name for debugging
     1417        MouseCursor = ImGuiMouseCursor_Arrow;
     1418
     1419        DragDropActive = DragDropWithinSource = DragDropWithinTarget = false;
     1420        DragDropSourceFlags = ImGuiDragDropFlags_None;
     1421        DragDropSourceFrameCount = -1;
     1422        DragDropMouseButton = -1;
     1423        DragDropTargetId = 0;
     1424        DragDropAcceptFlags = ImGuiDragDropFlags_None;
     1425        DragDropAcceptIdCurrRectSurface = 0.0f;
     1426        DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0;
     1427        DragDropAcceptFrameCount = -1;
     1428        DragDropHoldJustPressedId = 0;
     1429        memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal));
     1430
     1431        CurrentTabBar = NULL;
     1432
     1433        LastValidMousePos = ImVec2(0.0f, 0.0f);
     1434        TempInputId = 0;
     1435        ColorEditOptions = ImGuiColorEditFlags__OptionsDefault;
     1436        ColorEditLastHue = ColorEditLastSat = 0.0f;
     1437        ColorEditLastColor[0] = ColorEditLastColor[1] = ColorEditLastColor[2] = FLT_MAX;
     1438        SliderCurrentAccum = 0.0f;
     1439        SliderCurrentAccumDirty = false;
     1440        DragCurrentAccumDirty = false;
     1441        DragCurrentAccum = 0.0f;
     1442        DragSpeedDefaultRatio = 1.0f / 100.0f;
     1443        ScrollbarClickDeltaToGrabCenter = 0.0f;
     1444        TooltipOverrideCount = 0;
     1445
     1446        PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX);
     1447        PlatformLocaleDecimalPoint = '.';
     1448
     1449        SettingsLoaded = false;
     1450        SettingsDirtyTimer = 0.0f;
     1451
     1452        LogEnabled = false;
     1453        LogType = ImGuiLogType_None;
     1454        LogFile = NULL;
     1455        LogLinePosY = FLT_MAX;
     1456        LogLineFirstItem = false;
     1457        LogDepthRef = 0;
     1458        LogDepthToExpand = LogDepthToExpandDefault = 2;
     1459
     1460        DebugItemPickerActive = false;
     1461        DebugItemPickerBreakId = 0;
     1462
     1463        memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame));
     1464        FramerateSecPerFrameIdx = 0;
     1465        FramerateSecPerFrameAccum = 0.0f;
     1466        WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1;
     1467        memset(TempBuffer, 0, sizeof(TempBuffer));
     1468    }
     1469};
     1470
     1471//-----------------------------------------------------------------------------
     1472// [SECTION] ImGuiWindowTempData, ImGuiWindow
     1473//-----------------------------------------------------------------------------
     1474
     1475// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow.
     1476// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered.
     1477struct IMGUI_API ImGuiWindowTempData
     1478{
     1479    // Layout
     1480    ImVec2                  CursorPos;              // Current emitting position, in absolute coordinates.
     1481    ImVec2                  CursorPosPrevLine;
     1482    ImVec2                  CursorStartPos;         // Initial position after Begin(), generally ~ window position + WindowPadding.
     1483    ImVec2                  CursorMaxPos;           // Used to implicitly calculate the size of our contents, always growing during the frame. Used to calculate window->ContentSize at the beginning of next frame
     1484    ImVec2                  CurrLineSize;
     1485    ImVec2                  PrevLineSize;
     1486    float                   CurrLineTextBaseOffset; // Baseline offset (0.0f by default on a new line, generally == style.FramePadding.y when a framed item has been added).
     1487    float                   PrevLineTextBaseOffset;
     1488    ImVec1                  Indent;                 // Indentation / start position from left of window (increased by TreePush/TreePop, etc.)
     1489    ImVec1                  ColumnsOffset;          // Offset to the current column (if ColumnsCurrent > 0). FIXME: This and the above should be a stack to allow use cases like Tree->Column->Tree. Need revamp columns API.
     1490    ImVec1                  GroupOffset;
     1491
     1492    // Last item status
     1493    ImGuiID                 LastItemId;             // ID for last item
     1494    ImGuiItemStatusFlags    LastItemStatusFlags;    // Status flags for last item (see ImGuiItemStatusFlags_)
     1495    ImRect                  LastItemRect;           // Interaction rect for last item
     1496    ImRect                  LastItemDisplayRect;    // End-user display rect for last item (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
     1497
     1498    // Keyboard/Gamepad navigation
     1499    ImGuiNavLayer           NavLayerCurrent;        // Current layer, 0..31 (we currently only use 0..1)
     1500    int                     NavLayerActiveMask;     // Which layers have been written to (result from previous frame)
     1501    int                     NavLayerActiveMaskNext; // Which layers have been written to (accumulator for current frame)
     1502    ImGuiID                 NavFocusScopeIdCurrent; // Current focus scope ID while appending
     1503    bool                    NavHideHighlightOneFrame;
     1504    bool                    NavHasScroll;           // Set when scrolling can be used (ScrollMax > 0.0f)
     1505
     1506    // Miscellaneous
     1507    bool                    MenuBarAppending;       // FIXME: Remove this
     1508    ImVec2                  MenuBarOffset;          // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.
     1509    ImGuiMenuColumns        MenuColumns;            // Simplified columns storage for menu items measurement
     1510    int                     TreeDepth;              // Current tree depth.
     1511    ImU32                   TreeJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary.
     1512    ImVector<ImGuiWindow*>  ChildWindows;
     1513    ImGuiStorage*           StateStorage;           // Current persistent per-window storage (store e.g. tree node open/close state)
     1514    ImGuiColumns*           CurrentColumns;         // Current columns set
     1515    ImGuiLayoutType         LayoutType;
     1516    ImGuiLayoutType         ParentLayoutType;       // Layout type of parent window at the time of Begin()
     1517    int                     FocusCounterRegular;    // (Legacy Focus/Tabbing system) Sequential counter, start at -1 and increase as assigned via FocusableItemRegister() (FIXME-NAV: Needs redesign)
     1518    int                     FocusCounterTabStop;    // (Legacy Focus/Tabbing system) Same, but only count widgets which you can Tab through.
     1519
     1520    // Local parameters stacks
     1521    // We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
     1522    ImGuiItemFlags          ItemFlags;              // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default]
     1523    float                   ItemWidth;              // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window
     1524    float                   TextWrapPos;            // == TextWrapPosStack.back() [empty == -1.0f]
     1525    ImVector<ImGuiItemFlags>ItemFlagsStack;
     1526    ImVector<float>         ItemWidthStack;
     1527    ImVector<float>         TextWrapPosStack;
     1528    ImVector<ImGuiGroupData>GroupStack;
     1529    short                   StackSizesBackup[6];    // Store size of various stacks for asserting
     1530
     1531    ImGuiWindowTempData()
     1532    {
     1533        CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f);
     1534        CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f);
     1535        CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f;
     1536        Indent = ImVec1(0.0f);
     1537        ColumnsOffset = ImVec1(0.0f);
     1538        GroupOffset = ImVec1(0.0f);
     1539
     1540        LastItemId = 0;
     1541        LastItemStatusFlags = ImGuiItemStatusFlags_None;
     1542        LastItemRect = LastItemDisplayRect = ImRect();
     1543
     1544        NavLayerActiveMask = NavLayerActiveMaskNext = 0x00;
     1545        NavLayerCurrent = ImGuiNavLayer_Main;
     1546        NavFocusScopeIdCurrent = 0;
     1547        NavHideHighlightOneFrame = false;
     1548        NavHasScroll = false;
     1549
     1550        MenuBarAppending = false;
     1551        MenuBarOffset = ImVec2(0.0f, 0.0f);
     1552        TreeDepth = 0;
     1553        TreeJumpToParentOnPopMask = 0x00;
     1554        StateStorage = NULL;
     1555        CurrentColumns = NULL;
     1556        LayoutType = ParentLayoutType = ImGuiLayoutType_Vertical;
     1557        FocusCounterRegular = FocusCounterTabStop = -1;
     1558
     1559        ItemFlags = ImGuiItemFlags_Default_;
     1560        ItemWidth = 0.0f;
     1561        TextWrapPos = -1.0f;
     1562        memset(StackSizesBackup, 0, sizeof(StackSizesBackup));
     1563    }
     1564};
     1565
     1566// Storage for one window
    8911567struct IMGUI_API ImGuiWindow
    8921568{
    893    char*                   Name;
    894    ImGuiID                 ID;                                 // == ImHash(Name)
    895    ImGuiWindowFlags        Flags;                              // See enum ImGuiWindowFlags_
    896    ImVec2                  Pos;                                // Position (always rounded-up to nearest pixel)
    897    ImVec2                  Size;                               // Current size (==SizeFull or collapsed title bar size)
    898    ImVec2                  SizeFull;                           // Size when non collapsed
    899    ImVec2                  SizeFullAtLastBegin;                // Copy of SizeFull at the end of Begin. This is the reference value we'll use on the next frame to decide if we need scrollbars.
    900    ImVec2                  SizeContents;                       // Size of contents (== extents reach of the drawing cursor) from previous frame. Include decoration, window title, border, menu, etc.
    901    ImVec2                  SizeContentsExplicit;               // Size of contents explicitly set by the user via SetNextWindowContentSize()
    902    ImRect                  ContentsRegionRect;                 // Maximum visible content position in window coordinates. ~~ (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis
    903    ImVec2                  WindowPadding;                      // Window padding at the time of begin.
    904    float                   WindowRounding;                     // Window rounding at the time of begin.
    905    float                   WindowBorderSize;                   // Window border size at the time of begin.
    906    ImGuiID                 MoveId;                             // == window->GetID("#MOVE")
    907    ImGuiID                 ChildId;                            // Id of corresponding item in parent window (for child windows)
    908    ImVec2                  Scroll;
    909    ImVec2                  ScrollTarget;                       // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change)
    910    ImVec2                  ScrollTargetCenterRatio;            // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered
    911    ImVec2                  ScrollbarSizes;
    912    bool                    ScrollbarX, ScrollbarY;
    913    bool                    Active;                             // Set to true on Begin(), unless Collapsed
    914    bool                    WasActive;
    915    bool                    WriteAccessed;                      // Set to true when any widget access the current window
    916    bool                    Collapsed;                          // Set when collapsing window to become only title-bar
    917    bool                    CollapseToggleWanted;
    918    bool                    SkipItems;                          // Set when items can safely be all clipped (e.g. window not visible or collapsed)
    919    bool                    Appearing;                          // Set during the frame where the window is appearing (or re-appearing)
    920    bool                    CloseButton;                        // Set when the window has a close button (p_open != NULL)
    921    int                     BeginOrderWithinParent;             // Order within immediate parent window, if we are a child window. Otherwise 0.
    922    int                     BeginOrderWithinContext;            // Order within entire imgui context. This is mostly used for debugging submission order related issues.
    923    int                     BeginCount;                         // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
    924    ImGuiID                 PopupId;                            // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
    925    int                     AutoFitFramesX, AutoFitFramesY;
    926    bool                    AutoFitOnlyGrows;
    927    int                     AutoFitChildAxises;
    928    ImGuiDir                AutoPosLastDirection;
    929    int                     HiddenFrames;
    930    ImGuiCond               SetWindowPosAllowFlags;             // store acceptable condition flags for SetNextWindowPos() use.
    931    ImGuiCond               SetWindowSizeAllowFlags;            // store acceptable condition flags for SetNextWindowSize() use.
    932    ImGuiCond               SetWindowCollapsedAllowFlags;       // store acceptable condition flags for SetNextWindowCollapsed() use.
    933    ImVec2                  SetWindowPosVal;                    // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size)
    934    ImVec2                  SetWindowPosPivot;                  // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right.
    935 
    936    ImGuiDrawContext        DC;                                 // Temporary per-window data, reset at the beginning of the frame
    937    ImVector<ImGuiID>       IDStack;                            // ID stack. ID are hashes seeded with the value at the top of the stack
    938    ImRect                  ClipRect;                           // = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2.
    939    ImRect                  WindowRectClipped;                  // = WindowRect just after setup in Begin(). == window->Rect() for root window.
    940    ImRect                  InnerRect, InnerClipRect;
    941    int                     LastFrameActive;
    942    float                   ItemWidthDefault;
    943    ImGuiMenuColumns        MenuColumns;                        // Simplified columns storage for menu items
    944    ImGuiStorage            StateStorage;
    945    ImVector<ImGuiColumnsSet> ColumnsStorage;
    946    float                   FontWindowScale;                    // User scale multiplier per-window
    947 
    948    ImDrawList*             DrawList;                           // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
    949    ImDrawList              DrawListInst;
    950    ImGuiWindow*            ParentWindow;                       // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL.
    951    ImGuiWindow*            RootWindow;                         // Point to ourself or first ancestor that is not a child window.
    952    ImGuiWindow*            RootWindowForTitleBarHighlight;     // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.
    953    ImGuiWindow*            RootWindowForTabbing;               // Point to ourself or first ancestor which can be CTRL-Tabbed into.
    954    ImGuiWindow*            RootWindowForNav;                   // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
    955 
    956    ImGuiWindow*            NavLastChildNavWindow;              // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.)
    957    ImGuiID                 NavLastIds[2];                      // Last known NavId for this window, per layer (0/1)
    958    ImRect                  NavRectRel[2];                      // Reference rectangle, in window relative space
    959 
    960                                                                // Navigation / Focus
    961                                                                // FIXME-NAV: Merge all this with the new Nav system, at least the request variables should be moved to ImGuiContext
    962    int                     FocusIdxAllCounter;                 // Start at -1 and increase as assigned via FocusItemRegister()
    963    int                     FocusIdxTabCounter;                 // (same, but only count widgets which you can Tab through)
    964    int                     FocusIdxAllRequestCurrent;          // Item being requested for focus
    965    int                     FocusIdxTabRequestCurrent;          // Tab-able item being requested for focus
    966    int                     FocusIdxAllRequestNext;             // Item being requested for focus, for next update (relies on layout to be stable between the frame pressing TAB and the next frame)
    967    int                     FocusIdxTabRequestNext;             // "
     1569    char*                   Name;                               // Window name, owned by the window.
     1570    ImGuiID                 ID;                                 // == ImHashStr(Name)
     1571    ImGuiWindowFlags        Flags;                              // See enum ImGuiWindowFlags_
     1572    ImVec2                  Pos;                                // Position (always rounded-up to nearest pixel)
     1573    ImVec2                  Size;                               // Current size (==SizeFull or collapsed title bar size)
     1574    ImVec2                  SizeFull;                           // Size when non collapsed
     1575    ImVec2                  ContentSize;                        // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding.
     1576    ImVec2                  ContentSizeExplicit;                // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize().
     1577    ImVec2                  WindowPadding;                      // Window padding at the time of Begin().
     1578    float                   WindowRounding;                     // Window rounding at the time of Begin(). May be clamped lower to avoid rendering artifacts with title bar, menu bar etc.
     1579    float                   WindowBorderSize;                   // Window border size at the time of Begin().
     1580    int                     NameBufLen;                         // Size of buffer storing Name. May be larger than strlen(Name)!
     1581    ImGuiID                 MoveId;                             // == window->GetID("#MOVE")
     1582    ImGuiID                 ChildId;                            // ID of corresponding item in parent window (for navigation to return from child window to parent window)
     1583    ImVec2                  Scroll;
     1584    ImVec2                  ScrollMax;
     1585    ImVec2                  ScrollTarget;                       // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change)
     1586    ImVec2                  ScrollTargetCenterRatio;            // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered
     1587    ImVec2                  ScrollTargetEdgeSnapDist;           // 0.0f = no snapping, >0.0f snapping threshold
     1588    ImVec2                  ScrollbarSizes;                     // Size taken by each scrollbars on their smaller axis. Pay attention! ScrollbarSizes.x == width of the vertical scrollbar, ScrollbarSizes.y = height of the horizontal scrollbar.
     1589    bool                    ScrollbarX, ScrollbarY;             // Are scrollbars visible?
     1590    bool                    Active;                             // Set to true on Begin(), unless Collapsed
     1591    bool                    WasActive;
     1592    bool                    WriteAccessed;                      // Set to true when any widget access the current window
     1593    bool                    Collapsed;                          // Set when collapsing window to become only title-bar
     1594    bool                    WantCollapseToggle;
     1595    bool                    SkipItems;                          // Set when items can safely be all clipped (e.g. window not visible or collapsed)
     1596    bool                    Appearing;                          // Set during the frame where the window is appearing (or re-appearing)
     1597    bool                    Hidden;                             // Do not display (== HiddenFrames*** > 0)
     1598    bool                    IsFallbackWindow;                   // Set on the "Debug##Default" window.
     1599    bool                    HasCloseButton;                     // Set when the window has a close button (p_open != NULL)
     1600    signed char             ResizeBorderHeld;                   // Current border being held for resize (-1: none, otherwise 0-3)
     1601    short                   BeginCount;                         // Number of Begin() during the current frame (generally 0 or 1, 1+ if appending via multiple Begin/End pairs)
     1602    short                   BeginOrderWithinParent;             // Order within immediate parent window, if we are a child window. Otherwise 0.
     1603    short                   BeginOrderWithinContext;            // Order within entire imgui context. This is mostly used for debugging submission order related issues.
     1604    ImGuiID                 PopupId;                            // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
     1605    ImS8                    AutoFitFramesX, AutoFitFramesY;
     1606    ImS8                    AutoFitChildAxises;
     1607    bool                    AutoFitOnlyGrows;
     1608    ImGuiDir                AutoPosLastDirection;
     1609    int                     HiddenFramesCanSkipItems;           // Hide the window for N frames
     1610    int                     HiddenFramesCannotSkipItems;        // Hide the window for N frames while allowing items to be submitted so we can measure their size
     1611    ImGuiCond               SetWindowPosAllowFlags;             // store acceptable condition flags for SetNextWindowPos() use.
     1612    ImGuiCond               SetWindowSizeAllowFlags;            // store acceptable condition flags for SetNextWindowSize() use.
     1613    ImGuiCond               SetWindowCollapsedAllowFlags;       // store acceptable condition flags for SetNextWindowCollapsed() use.
     1614    ImVec2                  SetWindowPosVal;                    // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size)
     1615    ImVec2                  SetWindowPosPivot;                  // store window pivot for positioning. ImVec2(0, 0) when positioning from top-left corner; ImVec2(0.5f, 0.5f) for centering; ImVec2(1, 1) for bottom right.
     1616
     1617    ImVector<ImGuiID>       IDStack;                            // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure)
     1618    ImGuiWindowTempData     DC;                                 // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name.
     1619
     1620    // The best way to understand what those rectangles are is to use the 'Metrics -> Tools -> Show windows rectangles' viewer.
     1621    // The main 'OuterRect', omitted as a field, is window->Rect().
     1622    ImRect                  OuterRectClipped;                   // == Window->Rect() just after setup in Begin(). == window->Rect() for root window.
     1623    ImRect                  InnerRect;                          // Inner rectangle (omit title bar, menu bar, scroll bar)
     1624    ImRect                  InnerClipRect;                      // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect.
     1625    ImRect                  WorkRect;                           // Initially covers the whole scrolling region. Reduced by containers e.g columns/tables when active. Shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentRegionRect over time (from 1.71+ onward).
     1626    ImRect                  ParentWorkRect;                     // Backup of WorkRect before entering a container such as columns/tables. Used by e.g. SpanAllColumns functions to easily access. Stacked containers are responsible for maintaining this. // FIXME-WORKRECT: Could be a stack?
     1627    ImRect                  ClipRect;                           // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back().
     1628    ImRect                  ContentRegionRect;                  // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on.
     1629    ImVec2ih                HitTestHoleSize;                    // Define an optional rectangular hole where mouse will pass-through the window.
     1630    ImVec2ih                HitTestHoleOffset;
     1631
     1632    int                     LastFrameActive;                    // Last frame number the window was Active.
     1633    float                   LastTimeActive;                     // Last timestamp the window was Active (using float as we don't need high precision there)
     1634    float                   ItemWidthDefault;
     1635    ImGuiStorage            StateStorage;
     1636    ImVector<ImGuiColumns>  ColumnsStorage;
     1637    float                   FontWindowScale;                    // User scale multiplier per-window, via SetWindowFontScale()
     1638    int                     SettingsOffset;                     // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back)
     1639
     1640    ImDrawList*             DrawList;                           // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
     1641    ImDrawList              DrawListInst;
     1642    ImGuiWindow*            ParentWindow;                       // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL.
     1643    ImGuiWindow*            RootWindow;                         // Point to ourself or first ancestor that is not a child window == Top-level window.
     1644    ImGuiWindow*            RootWindowForTitleBarHighlight;     // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.
     1645    ImGuiWindow*            RootWindowForNav;                   // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
     1646
     1647    ImGuiWindow*            NavLastChildNavWindow;              // When going to the menu bar, we remember the child window we came from. (This could probably be made implicit if we kept g.Windows sorted by last focused including child window.)
     1648    ImGuiID                 NavLastIds[ImGuiNavLayer_COUNT];    // Last known NavId for this window, per layer (0/1)
     1649    ImRect                  NavRectRel[ImGuiNavLayer_COUNT];    // Reference rectangle, in window relative space
     1650
     1651    bool                    MemoryCompacted;                    // Set when window extraneous data have been garbage collected
     1652    int                     MemoryDrawListIdxCapacity;          // Backup of last idx/vtx count, so when waking up the window we can preallocate and avoid iterative alloc/copy
     1653    int                     MemoryDrawListVtxCapacity;
    9681654
    9691655public:
    970    ImGuiWindow(ImGuiContext* context, const char* name);
    971    ~ImGuiWindow();
    972 
    973    ImGuiID     GetID(const char* str, const char* str_end = NULL);
    974    ImGuiID     GetID(const void* ptr);
    975    ImGuiID     GetIDNoKeepAlive(const char* str, const char* str_end = NULL);
    976    ImGuiID     GetIDFromRectangle(const ImRect& r_abs);
    977 
    978    // We don't use g.FontSize because the window may be != g.CurrentWidow.
    979    ImRect      Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
    980    float       CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; }
    981    float       TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; }
    982    ImRect      TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
    983    float       MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; }
    984    ImRect      MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
    985 };
    986 
    987 // Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data. 
    988 struct ImGuiItemHoveredDataBackup
    989 {
    990    ImGuiID                 LastItemId;
    991    ImGuiItemStatusFlags    LastItemStatusFlags;
    992    ImRect                  LastItemRect;
    993    ImRect                  LastItemDisplayRect;
    994 
    995    ImGuiItemHoveredDataBackup() { Backup(); }
    996    void Backup() { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; }
    997    void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; }
    998 };
    999 
    1000 //-----------------------------------------------------------------------------
    1001 // Internal API
    1002 // No guarantee of forward compatibility here.
     1656    ImGuiWindow(ImGuiContext* context, const char* name);
     1657    ~ImGuiWindow();
     1658
     1659    ImGuiID     GetID(const char* str, const char* str_end = NULL);
     1660    ImGuiID     GetID(const void* ptr);
     1661    ImGuiID     GetID(int n);
     1662    ImGuiID     GetIDNoKeepAlive(const char* str, const char* str_end = NULL);
     1663    ImGuiID     GetIDNoKeepAlive(const void* ptr);
     1664    ImGuiID     GetIDNoKeepAlive(int n);
     1665    ImGuiID     GetIDFromRectangle(const ImRect& r_abs);
     1666
     1667    // We don't use g.FontSize because the window may be != g.CurrentWidow.
     1668    ImRect      Rect() const            { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
     1669    float       CalcFontSize() const    { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; }
     1670    float       TitleBarHeight() const  { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; }
     1671    ImRect      TitleBarRect() const    { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
     1672    float       MenuBarHeight() const   { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; }
     1673    ImRect      MenuBarRect() const     { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
     1674};
     1675
     1676// Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data.
     1677struct ImGuiLastItemDataBackup
     1678{
     1679    ImGuiID                 LastItemId;
     1680    ImGuiItemStatusFlags    LastItemStatusFlags;
     1681    ImRect                  LastItemRect;
     1682    ImRect                  LastItemDisplayRect;
     1683
     1684    ImGuiLastItemDataBackup() { Backup(); }
     1685    void Backup()           { ImGuiWindow* window = GImGui->CurrentWindow; LastItemId = window->DC.LastItemId; LastItemStatusFlags = window->DC.LastItemStatusFlags; LastItemRect = window->DC.LastItemRect; LastItemDisplayRect = window->DC.LastItemDisplayRect; }
     1686    void Restore() const    { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; }
     1687};
     1688
     1689//-----------------------------------------------------------------------------
     1690// [SECTION] Tab bar, Tab item support
     1691//-----------------------------------------------------------------------------
     1692
     1693// Extend ImGuiTabBarFlags_
     1694enum ImGuiTabBarFlagsPrivate_
     1695{
     1696    ImGuiTabBarFlags_DockNode                   = 1 << 20,  // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around]
     1697    ImGuiTabBarFlags_IsFocused                  = 1 << 21,
     1698    ImGuiTabBarFlags_SaveSettings               = 1 << 22   // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
     1699};
     1700
     1701// Extend ImGuiTabItemFlags_
     1702enum ImGuiTabItemFlagsPrivate_
     1703{
     1704    ImGuiTabItemFlags_NoCloseButton             = 1 << 20,  // Track whether p_open was set or not (we'll need this info on the next frame to recompute ContentWidth during layout)
     1705    ImGuiTabItemFlags_Button                    = 1 << 21   // Used by TabItemButton, change the tab item behavior to mimic a button
     1706};
     1707
     1708// Storage for one active tab item (sizeof() 28~32 bytes)
     1709struct ImGuiTabItem
     1710{
     1711    ImGuiID             ID;
     1712    ImGuiTabItemFlags   Flags;
     1713    int                 LastFrameVisible;
     1714    int                 LastFrameSelected;      // This allows us to infer an ordered list of the last activated tabs with little maintenance
     1715    float               Offset;                 // Position relative to beginning of tab
     1716    float               Width;                  // Width currently displayed
     1717    float               ContentWidth;           // Width of label, stored during BeginTabItem() call
     1718    ImS16               NameOffset;             // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
     1719    ImS8                BeginOrder;             // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable
     1720    ImS8                IndexDuringLayout;      // Index only used during TabBarLayout()
     1721    bool                WantClose;              // Marked as closed by SetTabItemClosed()
     1722
     1723    ImGuiTabItem()      { ID = 0; Flags = ImGuiTabItemFlags_None; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = ContentWidth = 0.0f; BeginOrder = -1; IndexDuringLayout = -1; WantClose = false; }
     1724};
     1725
     1726// Storage for a tab bar (sizeof() 92~96 bytes)
     1727struct ImGuiTabBar
     1728{
     1729    ImVector<ImGuiTabItem> Tabs;
     1730    ImGuiID             ID;                     // Zero for tab-bars used by docking
     1731    ImGuiID             SelectedTabId;          // Selected tab/window
     1732    ImGuiID             NextSelectedTabId;
     1733    ImGuiID             VisibleTabId;           // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview)
     1734    int                 CurrFrameVisible;
     1735    int                 PrevFrameVisible;
     1736    ImRect              BarRect;
     1737    float               LastTabContentHeight;   // Record the height of contents submitted below the tab bar
     1738    float               WidthAllTabs;           // Actual width of all tabs (locked during layout)
     1739    float               WidthAllTabsIdeal;      // Ideal width if all tabs were visible and not clipped
     1740    float               ScrollingAnim;
     1741    float               ScrollingTarget;
     1742    float               ScrollingTargetDistToVisibility;
     1743    float               ScrollingSpeed;
     1744    float               ScrollingRectMinX;
     1745    float               ScrollingRectMaxX;
     1746    ImGuiTabBarFlags    Flags;
     1747    ImGuiID             ReorderRequestTabId;
     1748    ImS8                ReorderRequestDir;
     1749    ImS8                TabsActiveCount;        // Number of tabs submitted this frame.
     1750    bool                WantLayout;
     1751    bool                VisibleTabWasSubmitted;
     1752    bool                TabsAddedNew;           // Set to true when a new tab item or button has been added to the tab bar during last frame
     1753    short               LastTabItemIdx;         // Index of last BeginTabItem() tab for use by EndTabItem()
     1754    ImVec2              FramePadding;           // style.FramePadding locked at the time of BeginTabBar()
     1755    ImGuiTextBuffer     TabsNames;              // For non-docking tab bar we re-append names in a contiguous buffer.
     1756
     1757    ImGuiTabBar();
     1758    int                 GetTabOrder(const ImGuiTabItem* tab) const  { return Tabs.index_from_ptr(tab); }
     1759    const char*         GetTabName(const ImGuiTabItem* tab) const
     1760    {
     1761        IM_ASSERT(tab->NameOffset != -1 && (int)tab->NameOffset < TabsNames.Buf.Size);
     1762        return TabsNames.Buf.Data + tab->NameOffset;
     1763    }
     1764};
     1765
     1766//-----------------------------------------------------------------------------
     1767// [SECTION] Table support
     1768//-----------------------------------------------------------------------------
     1769
     1770#ifdef IMGUI_HAS_TABLE
     1771// <this is filled in 'tables' branch>
     1772#endif // #ifdef IMGUI_HAS_TABLE
     1773
     1774//-----------------------------------------------------------------------------
     1775// [SECTION] Internal API
     1776// No guarantee of forward compatibility here!
    10031777//-----------------------------------------------------------------------------
    10041778
    10051779namespace ImGui
    10061780{
    1007    // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window)
    1008    // If this ever crash because g.CurrentWindow is NULL it means that either
    1009    // - ImGui::NewFrame() has never been called, which is illegal.
    1010    // - You are calling ImGui functions after ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
    1011    inline    ImGuiWindow*  GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
    1012    inline    ImGuiWindow*  GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
    1013    IMGUI_API ImGuiWindow*  FindWindowByName(const char* name);
    1014    IMGUI_API void          FocusWindow(ImGuiWindow* window);
    1015    IMGUI_API void          BringWindowToFront(ImGuiWindow* window);
    1016    IMGUI_API void          BringWindowToBack(ImGuiWindow* window);
    1017    IMGUI_API bool          IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
    1018    IMGUI_API bool          IsWindowNavFocusable(ImGuiWindow* window);
    1019 
    1020    IMGUI_API void          Initialize(ImGuiContext* context);
    1021    IMGUI_API void          Shutdown(ImGuiContext* context);    // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext().
    1022 
    1023    IMGUI_API void          NewFrameUpdateHoveredWindowAndCaptureFlags();
    1024 
    1025    IMGUI_API void                  MarkIniSettingsDirty();
    1026    IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name);
    1027    IMGUI_API ImGuiWindowSettings*  FindWindowSettings(ImGuiID id);
    1028 
    1029    IMGUI_API void          SetActiveID(ImGuiID id, ImGuiWindow* window);
    1030    IMGUI_API ImGuiID       GetActiveID();
    1031    IMGUI_API void          SetFocusID(ImGuiID id, ImGuiWindow* window);
    1032    IMGUI_API void          ClearActiveID();
    1033    IMGUI_API void          SetHoveredID(ImGuiID id);
    1034    IMGUI_API ImGuiID       GetHoveredID();
    1035    IMGUI_API void          KeepAliveID(ImGuiID id);
    1036 
    1037    IMGUI_API void          ItemSize(const ImVec2& size, float text_offset_y = 0.0f);
    1038    IMGUI_API void          ItemSize(const ImRect& bb, float text_offset_y = 0.0f);
    1039    IMGUI_API bool          ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL);
    1040    IMGUI_API bool          ItemHoverable(const ImRect& bb, ImGuiID id);
    1041    IMGUI_API bool          IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
    1042    IMGUI_API bool          FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop = true);      // Return true if focus is requested
    1043    IMGUI_API void          FocusableItemUnregister(ImGuiWindow* window);
    1044    IMGUI_API ImVec2        CalcItemSize(ImVec2 size, float default_x, float default_y);
    1045    IMGUI_API float         CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
    1046    IMGUI_API void          PushMultiItemsWidths(int components, float width_full = 0.0f);
    1047    IMGUI_API void          PushItemFlag(ImGuiItemFlags option, bool enabled);
    1048    IMGUI_API void          PopItemFlag();
    1049 
    1050    IMGUI_API void          SetCurrentFont(ImFont* font);
    1051 
    1052    IMGUI_API void          OpenPopupEx(ImGuiID id);
    1053    IMGUI_API void          ClosePopup(ImGuiID id);
    1054    IMGUI_API void          ClosePopupsOverWindow(ImGuiWindow* ref_window);
    1055    IMGUI_API bool          IsPopupOpen(ImGuiID id);
    1056    IMGUI_API bool          BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
    1057    IMGUI_API void          BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true);
    1058    IMGUI_API ImGuiWindow*  GetFrontMostPopupModal();
    1059 
    1060    IMGUI_API void          NavInitWindow(ImGuiWindow* window, bool force_reinit);
    1061    IMGUI_API void          NavMoveRequestCancel();
    1062    IMGUI_API void          ActivateItem(ImGuiID id);   // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again.
    1063 
    1064    IMGUI_API float         GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode);
    1065    IMGUI_API ImVec2        GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f);
    1066    IMGUI_API int           CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate);
    1067 
    1068    IMGUI_API void          Scrollbar(ImGuiLayoutType direction);
    1069    IMGUI_API void          VerticalSeparator();        // Vertical separator, for menu bars (use current line height). not exposed because it is misleading what it doesn't have an effect on regular layout.
    1070    IMGUI_API bool          SplitterBehavior(ImGuiID id, const ImRect& bb, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f);
    1071 
    1072    IMGUI_API bool          BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
    1073    IMGUI_API void          ClearDragDrop();
    1074    IMGUI_API bool          IsDragDropPayloadBeingAccepted();
    1075 
    1076    // FIXME-WIP: New Columns API
    1077    IMGUI_API void          BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns().
    1078    IMGUI_API void          EndColumns();                                                             // close columns
    1079    IMGUI_API void          PushColumnClipRect(int column_index = -1);
    1080 
    1081    // NB: All position are in absolute pixels coordinates (never using window coordinates internally)
    1082    // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT.
    1083    IMGUI_API void          RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
    1084    IMGUI_API void          RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
    1085    IMGUI_API void          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 = ImVec2(0, 0), const ImRect* clip_rect = NULL);
    1086    IMGUI_API void          RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
    1087    IMGUI_API void          RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
    1088    IMGUI_API void          RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0);
    1089    IMGUI_API void          RenderArrow(ImVec2 pos, ImGuiDir dir, float scale = 1.0f);
    1090    IMGUI_API void          RenderBullet(ImVec2 pos);
    1091    IMGUI_API void          RenderCheckMark(ImVec2 pos, ImU32 col, float sz);
    1092    IMGUI_API void          RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight
    1093    IMGUI_API void          RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
    1094    IMGUI_API const char*   FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text.
    1095 
    1096    IMGUI_API bool          ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
    1097    IMGUI_API bool          ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
    1098    IMGUI_API bool          CloseButton(ImGuiID id, const ImVec2& pos, float radius);
    1099 
    1100    IMGUI_API bool          SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, const char* format, float power, ImGuiSliderFlags flags = 0);
    1101    IMGUI_API bool          SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* format, float power);
    1102    IMGUI_API bool          SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* format);
    1103 
    1104    IMGUI_API bool          DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, const char* format, float power);
    1105    IMGUI_API bool          DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* format, float power);
    1106    IMGUI_API bool          DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* format);
    1107 
    1108    IMGUI_API bool          InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback = NULL, void* user_data = NULL);
    1109    IMGUI_API bool          InputFloatN(const char* label, float* v, int components, const char* format, ImGuiInputTextFlags extra_flags);
    1110    IMGUI_API bool          InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags);
    1111    IMGUI_API bool          InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* format, ImGuiInputTextFlags extra_flags = 0);
    1112    IMGUI_API bool          InputScalarAsWidgetReplacement(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* data_ptr, const char* format);
    1113 
    1114    IMGUI_API void          ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags);
    1115    IMGUI_API void          ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags);
    1116 
    1117    IMGUI_API bool          TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
    1118    IMGUI_API bool          TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0);                     // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging
    1119    IMGUI_API void          TreePushRawID(ImGuiID id);
    1120 
    1121    IMGUI_API void          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);
    1122 
    1123    IMGUI_API const char*   ParseFormatTrimDecorationsLeading(const char* format);
    1124    IMGUI_API const char*   ParseFormatTrimDecorations(const char* format, char* buf, int buf_size);
    1125    IMGUI_API int           ParseFormatPrecision(const char* format, int default_value);
    1126    IMGUI_API float         RoundScalarWithFormat(const char* format, float value);
    1127 
    1128    // Shade functions (write over already created vertices)
    1129    IMGUI_API void          ShadeVertsLinearColorGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1);
    1130    IMGUI_API void          ShadeVertsLinearAlphaGradientForLeftToRightText(ImDrawVert* vert_start, ImDrawVert* vert_end, float gradient_p0_x, float gradient_p1_x);
    1131    IMGUI_API void          ShadeVertsLinearUV(ImDrawVert* vert_start, ImDrawVert* vert_end, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp);
     1781    // Windows
     1782    // We should always have a CurrentWindow in the stack (there is an implicit "Debug" window)
     1783    // If this ever crash because g.CurrentWindow is NULL it means that either
     1784    // - ImGui::NewFrame() has never been called, which is illegal.
     1785    // - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
     1786    inline    ImGuiWindow*  GetCurrentWindowRead()      { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
     1787    inline    ImGuiWindow*  GetCurrentWindow()          { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
     1788    IMGUI_API ImGuiWindow*  FindWindowByID(ImGuiID id);
     1789    IMGUI_API ImGuiWindow*  FindWindowByName(const char* name);
     1790    IMGUI_API void          UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window);
     1791    IMGUI_API ImVec2        CalcWindowExpectedSize(ImGuiWindow* window);
     1792    IMGUI_API bool          IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
     1793    IMGUI_API bool          IsWindowNavFocusable(ImGuiWindow* window);
     1794    IMGUI_API ImRect        GetWindowAllowedExtentRect(ImGuiWindow* window);
     1795    IMGUI_API void          SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);
     1796    IMGUI_API void          SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0);
     1797    IMGUI_API void          SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0);
     1798    IMGUI_API void          SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size);
     1799
     1800    // Windows: Display Order and Focus Order
     1801    IMGUI_API void          FocusWindow(ImGuiWindow* window);
     1802    IMGUI_API void          FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window);
     1803    IMGUI_API void          BringWindowToFocusFront(ImGuiWindow* window);
     1804    IMGUI_API void          BringWindowToDisplayFront(ImGuiWindow* window);
     1805    IMGUI_API void          BringWindowToDisplayBack(ImGuiWindow* window);
     1806
     1807    // Fonts, drawing
     1808    IMGUI_API void          SetCurrentFont(ImFont* font);
     1809    inline ImFont*          GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
     1810    inline ImDrawList*      GetForegroundDrawList(ImGuiWindow* window) { IM_UNUSED(window); ImGuiContext& g = *GImGui; return &g.ForegroundDrawList; } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches.
     1811
     1812    // Init
     1813    IMGUI_API void          Initialize(ImGuiContext* context);
     1814    IMGUI_API void          Shutdown(ImGuiContext* context);    // Since 1.60 this is a _private_ function. You can call DestroyContext() to destroy the context created by CreateContext().
     1815
     1816    // NewFrame
     1817    IMGUI_API void          UpdateHoveredWindowAndCaptureFlags();
     1818    IMGUI_API void          StartMouseMovingWindow(ImGuiWindow* window);
     1819    IMGUI_API void          UpdateMouseMovingWindowNewFrame();
     1820    IMGUI_API void          UpdateMouseMovingWindowEndFrame();
     1821
     1822    // Settings
     1823    IMGUI_API void                  MarkIniSettingsDirty();
     1824    IMGUI_API void                  MarkIniSettingsDirty(ImGuiWindow* window);
     1825    IMGUI_API void                  ClearIniSettings();
     1826    IMGUI_API ImGuiWindowSettings*  CreateNewWindowSettings(const char* name);
     1827    IMGUI_API ImGuiWindowSettings*  FindWindowSettings(ImGuiID id);
     1828    IMGUI_API ImGuiWindowSettings*  FindOrCreateWindowSettings(const char* name);
     1829    IMGUI_API ImGuiSettingsHandler* FindSettingsHandler(const char* type_name);
     1830
     1831    // Scrolling
     1832    IMGUI_API void          SetNextWindowScroll(const ImVec2& scroll); // Use -1.0f on one axis to leave as-is
     1833    IMGUI_API void          SetScrollX(ImGuiWindow* window, float scroll_x);
     1834    IMGUI_API void          SetScrollY(ImGuiWindow* window, float scroll_y);
     1835    IMGUI_API void          SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio);
     1836    IMGUI_API void          SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio);
     1837    IMGUI_API ImVec2        ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect);
     1838
     1839    // Basic Accessors
     1840    inline ImGuiID          GetItemID()     { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; }   // Get ID of last item (~~ often same ImGui::GetID(label) beforehand)
     1841    inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemStatusFlags; }
     1842    inline ImGuiID          GetActiveID()   { ImGuiContext& g = *GImGui; return g.ActiveId; }
     1843    inline ImGuiID          GetFocusID()    { ImGuiContext& g = *GImGui; return g.NavId; }
     1844    IMGUI_API void          SetActiveID(ImGuiID id, ImGuiWindow* window);
     1845    IMGUI_API void          SetFocusID(ImGuiID id, ImGuiWindow* window);
     1846    IMGUI_API void          ClearActiveID();
     1847    IMGUI_API ImGuiID       GetHoveredID();
     1848    IMGUI_API void          SetHoveredID(ImGuiID id);
     1849    IMGUI_API void          KeepAliveID(ImGuiID id);
     1850    IMGUI_API void          MarkItemEdited(ImGuiID id);     // Mark data associated to given item as "edited", used by IsItemDeactivatedAfterEdit() function.
     1851    IMGUI_API void          PushOverrideID(ImGuiID id);     // Push given value as-is at the top of the ID stack (whereas PushID combines old and new hashes)
     1852    IMGUI_API ImGuiID       GetIDWithSeed(const char* str_id_begin, const char* str_id_end, ImGuiID seed);
     1853
     1854    // Basic Helpers for widget code
     1855    IMGUI_API void          ItemSize(const ImVec2& size, float text_baseline_y = -1.0f);
     1856    IMGUI_API void          ItemSize(const ImRect& bb, float text_baseline_y = -1.0f);
     1857    IMGUI_API bool          ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb = NULL);
     1858    IMGUI_API bool          ItemHoverable(const ImRect& bb, ImGuiID id);
     1859    IMGUI_API bool          IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
     1860    IMGUI_API void          SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags status_flags, const ImRect& item_rect);
     1861    IMGUI_API bool          FocusableItemRegister(ImGuiWindow* window, ImGuiID id);   // Return true if focus is requested
     1862    IMGUI_API void          FocusableItemUnregister(ImGuiWindow* window);
     1863    IMGUI_API ImVec2        CalcItemSize(ImVec2 size, float default_w, float default_h);
     1864    IMGUI_API float         CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
     1865    IMGUI_API void          PushMultiItemsWidths(int components, float width_full);
     1866    IMGUI_API void          PushItemFlag(ImGuiItemFlags option, bool enabled);
     1867    IMGUI_API void          PopItemFlag();
     1868    IMGUI_API bool          IsItemToggledSelection();                                   // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly)
     1869    IMGUI_API ImVec2        GetContentRegionMaxAbs();
     1870    IMGUI_API void          ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);
     1871
     1872    // Logging/Capture
     1873    IMGUI_API void          LogBegin(ImGuiLogType type, int auto_open_depth);           // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name.
     1874    IMGUI_API void          LogToBuffer(int auto_open_depth = -1);                      // Start logging/capturing to internal buffer
     1875
     1876    // Popups, Modals, Tooltips
     1877    IMGUI_API bool          BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags);
     1878    IMGUI_API void          OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags = ImGuiPopupFlags_None);
     1879    IMGUI_API void          ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup);
     1880    IMGUI_API void          ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup);
     1881    IMGUI_API bool          IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags);
     1882    IMGUI_API bool          BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
     1883    IMGUI_API void          BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags);
     1884    IMGUI_API ImGuiWindow*  GetTopMostPopupModal();
     1885    IMGUI_API ImVec2        FindBestWindowPosForPopup(ImGuiWindow* window);
     1886    IMGUI_API ImVec2        FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy);
     1887
     1888    // Gamepad/Keyboard Navigation
     1889    IMGUI_API void          NavInitWindow(ImGuiWindow* window, bool force_reinit);
     1890    IMGUI_API bool          NavMoveRequestButNoResultYet();
     1891    IMGUI_API void          NavMoveRequestCancel();
     1892    IMGUI_API void          NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags);
     1893    IMGUI_API void          NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);
     1894    IMGUI_API float         GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode);
     1895    IMGUI_API ImVec2        GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor = 0.0f, float fast_factor = 0.0f);
     1896    IMGUI_API int           CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate);
     1897    IMGUI_API void          ActivateItem(ImGuiID id);   // Remotely activate a button, checkbox, tree node etc. given its unique ID. activation is queued and processed on the next frame when the item is encountered again.
     1898    IMGUI_API void          SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id);
     1899    IMGUI_API void          SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel);
     1900
     1901    // Focus Scope (WIP)
     1902    // This is generally used to identify a selection set (multiple of which may be in the same window), as selection
     1903    // patterns generally need to react (e.g. clear selection) when landing on an item of the set.
     1904    IMGUI_API void          PushFocusScope(ImGuiID id);
     1905    IMGUI_API void          PopFocusScope();
     1906    inline ImGuiID          GetFocusScopeID()               { ImGuiContext& g = *GImGui; return g.NavFocusScopeId; }
     1907
     1908    // Inputs
     1909    // FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions.
     1910    inline bool             IsActiveIdUsingNavDir(ImGuiDir dir)                         { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; }
     1911    inline bool             IsActiveIdUsingNavInput(ImGuiNavInput input)                { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; }
     1912    inline bool             IsActiveIdUsingKey(ImGuiKey key)                            { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; }
     1913    IMGUI_API bool          IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold = -1.0f);
     1914    inline bool             IsKeyPressedMap(ImGuiKey key, bool repeat = true)           { ImGuiContext& g = *GImGui; const int key_index = g.IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; }
     1915    inline bool             IsNavInputDown(ImGuiNavInput n)                             { ImGuiContext& g = *GImGui; return g.IO.NavInputs[n] > 0.0f; }
     1916    inline bool             IsNavInputTest(ImGuiNavInput n, ImGuiInputReadMode rm)      { return (GetNavInputAmount(n, rm) > 0.0f); }
     1917    IMGUI_API ImGuiKeyModFlags GetMergedKeyModFlags();
     1918
     1919    // Drag and Drop
     1920    IMGUI_API bool          BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
     1921    IMGUI_API void          ClearDragDrop();
     1922    IMGUI_API bool          IsDragDropPayloadBeingAccepted();
     1923
     1924    // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API)
     1925    IMGUI_API void          SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect);
     1926    IMGUI_API void          BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns().
     1927    IMGUI_API void          EndColumns();                                                             // close columns
     1928    IMGUI_API void          PushColumnClipRect(int column_index);
     1929    IMGUI_API void          PushColumnsBackground();
     1930    IMGUI_API void          PopColumnsBackground();
     1931    IMGUI_API ImGuiID       GetColumnsID(const char* str_id, int count);
     1932    IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id);
     1933    IMGUI_API float         GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm);
     1934    IMGUI_API float         GetColumnNormFromOffset(const ImGuiColumns* columns, float offset);
     1935
     1936    // Tab Bars
     1937    IMGUI_API bool          BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);
     1938    IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
     1939    IMGUI_API void          TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
     1940    IMGUI_API void          TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
     1941    IMGUI_API void          TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir);
     1942    IMGUI_API bool          TabBarProcessReorder(ImGuiTabBar* tab_bar);
     1943    IMGUI_API bool          TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags);
     1944    IMGUI_API ImVec2        TabItemCalcSize(const char* label, bool has_close_button);
     1945    IMGUI_API void          TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col);
     1946    IMGUI_API bool          TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id, bool is_contents_visible);
     1947
     1948    // Render helpers
     1949    // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT.
     1950    // NB: All position are in absolute pixels coordinates (we are never using window coordinates internally)
     1951    IMGUI_API void          RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
     1952    IMGUI_API void          RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
     1953    IMGUI_API void          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 = ImVec2(0, 0), const ImRect* clip_rect = NULL);
     1954    IMGUI_API void          RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);
     1955    IMGUI_API void          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, const ImVec2* text_size_if_known);
     1956    IMGUI_API void          RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
     1957    IMGUI_API void          RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
     1958    IMGUI_API void          RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0);
     1959    IMGUI_API void          RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight
     1960    IMGUI_API const char*   FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text.
     1961    IMGUI_API void          LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL);
     1962
     1963    // Render helpers (those functions don't access any ImGui state!)
     1964    IMGUI_API void          RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f);
     1965    IMGUI_API void          RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col);
     1966    IMGUI_API void          RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float sz);
     1967    IMGUI_API void          RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow);
     1968    IMGUI_API void          RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);
     1969    IMGUI_API void          RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
     1970    IMGUI_API void          RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding);
     1971
     1972#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
     1973    // [1.71: 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while]
     1974    inline void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f) { ImGuiWindow* window = GetCurrentWindow(); RenderArrow(window->DrawList, pos, GetColorU32(ImGuiCol_Text), dir, scale); }
     1975    inline void RenderBullet(ImVec2 pos)                                { ImGuiWindow* window = GetCurrentWindow(); RenderBullet(window->DrawList, pos, GetColorU32(ImGuiCol_Text)); }
     1976#endif
     1977
     1978    // Widgets
     1979    IMGUI_API void          TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0);
     1980    IMGUI_API bool          ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
     1981    IMGUI_API bool          CloseButton(ImGuiID id, const ImVec2& pos);
     1982    IMGUI_API bool          CollapseButton(ImGuiID id, const ImVec2& pos);
     1983    IMGUI_API bool          ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0);
     1984    IMGUI_API void          Scrollbar(ImGuiAxis axis);
     1985    IMGUI_API bool          ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners);
     1986    IMGUI_API bool          ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col);
     1987    IMGUI_API ImRect        GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis);
     1988    IMGUI_API ImGuiID       GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis);
     1989    IMGUI_API ImGuiID       GetWindowResizeID(ImGuiWindow* window, int n); // 0..3: corners, 4..7: borders
     1990    IMGUI_API void          SeparatorEx(ImGuiSeparatorFlags flags);
     1991
     1992    // Widgets low-level behaviors
     1993    IMGUI_API bool          ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
     1994    IMGUI_API bool          DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v_speed, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags);
     1995    IMGUI_API bool          SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* p_v, const void* p_min, const void* p_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb);
     1996    IMGUI_API bool          SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f);
     1997    IMGUI_API bool          TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
     1998    IMGUI_API bool          TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0);                     // Consume previous SetNextItemOpen() data, if any. May return true when logging
     1999    IMGUI_API void          TreePushOverrideID(ImGuiID id);
     2000
     2001    // Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
     2002    // To use them externally (for custom widget) you may need an "extern template" statement in your code in order to link to existing instances and silence Clang warnings (see #2036).
     2003    // e.g. " extern template IMGUI_API float RoundScalarWithFormatT<float, float>(const char* format, ImGuiDataType data_type, float v); "
     2004    template<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API float ScaleRatioFromValueT(ImGuiDataType data_type, T v, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size);
     2005    template<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API T     ScaleValueFromRatioT(ImGuiDataType data_type, float t, T v_min, T v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_size);
     2006    template<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API bool  DragBehaviorT(ImGuiDataType data_type, T* v, float v_speed, T v_min, T v_max, const char* format, ImGuiSliderFlags flags);
     2007    template<typename T, typename SIGNED_T, typename FLOAT_T>   IMGUI_API bool  SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, T* v, T v_min, T v_max, const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb);
     2008    template<typename T, typename SIGNED_T>                     IMGUI_API T     RoundScalarWithFormatT(const char* format, ImGuiDataType data_type, T v);
     2009
     2010    // Data type helpers
     2011    IMGUI_API const ImGuiDataTypeInfo*  DataTypeGetInfo(ImGuiDataType data_type);
     2012    IMGUI_API int           DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* p_data, const char* format);
     2013    IMGUI_API void          DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, const void* arg_1, const void* arg_2);
     2014    IMGUI_API bool          DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* p_data, const char* format);
     2015    IMGUI_API int           DataTypeCompare(ImGuiDataType data_type, const void* arg_1, const void* arg_2);
     2016    IMGUI_API bool          DataTypeClamp(ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max);
     2017
     2018    // InputText
     2019    IMGUI_API bool          InputTextEx(const char* label, const char* hint, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback = NULL, void* user_data = NULL);
     2020    IMGUI_API bool          TempInputText(const ImRect& bb, ImGuiID id, const char* label, char* buf, int buf_size, ImGuiInputTextFlags flags);
     2021    IMGUI_API bool          TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min = NULL, const void* p_clamp_max = NULL);
     2022    inline bool             TempInputIsActive(ImGuiID id)       { ImGuiContext& g = *GImGui; return (g.ActiveId == id && g.TempInputId == id); }
     2023    inline ImGuiInputTextState* GetInputTextState(ImGuiID id)   { ImGuiContext& g = *GImGui; return (g.InputTextState.ID == id) ? &g.InputTextState : NULL; } // Get input text state if active
     2024
     2025    // Color
     2026    IMGUI_API void          ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags);
     2027    IMGUI_API void          ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags);
     2028    IMGUI_API void          ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags);
     2029
     2030    // Plot
     2031    IMGUI_API int           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 frame_size);
     2032
     2033    // Shade functions (write over already created vertices)
     2034    IMGUI_API void          ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1);
     2035    IMGUI_API void          ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp);
     2036
     2037    // Garbage collection
     2038    IMGUI_API void          GcCompactTransientWindowBuffers(ImGuiWindow* window);
     2039    IMGUI_API void          GcAwakeTransientWindowBuffers(ImGuiWindow* window);
     2040
     2041    // Debug Tools
     2042    inline void             DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255))    { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(window->DC.LastItemRect.Min, window->DC.LastItemRect.Max, col); }
     2043    inline void             DebugStartItemPicker()                                  { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; }
    11322044
    11332045} // namespace ImGui
    11342046
    1135   // ImFontAtlas internals
     2047// ImFontAtlas internals
    11362048IMGUI_API bool              ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
    1137 IMGUI_API void              ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas);
     2049IMGUI_API void              ImFontAtlasBuildInit(ImFontAtlas* atlas);
    11382050IMGUI_API void              ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
    1139 IMGUI_API void              ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc);
     2051IMGUI_API void              ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque);
    11402052IMGUI_API void              ImFontAtlasBuildFinish(ImFontAtlas* atlas);
     2053IMGUI_API void              ImFontAtlasBuildRender1bppRectFromString(ImFontAtlas* atlas, int atlas_x, int atlas_y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value);
    11412054IMGUI_API void              ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
    11422055IMGUI_API void              ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
    11432056
    1144 #ifdef __clang__
     2057//-----------------------------------------------------------------------------
     2058// [SECTION] Test Engine Hooks (imgui_test_engine)
     2059//-----------------------------------------------------------------------------
     2060
     2061#ifdef IMGUI_ENABLE_TEST_ENGINE
     2062extern void                 ImGuiTestEngineHook_Shutdown(ImGuiContext* ctx);
     2063extern void                 ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx);
     2064extern void                 ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx);
     2065extern void                 ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id);
     2066extern void                 ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags);
     2067extern void                 ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id);
     2068extern void                 ImGuiTestEngineHook_IdInfo(ImGuiContext* ctx, ImGuiDataType data_type, ImGuiID id, const void* data_id, const void* data_id_end);
     2069extern void                 ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...);
     2070#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID)                 if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID)               // Register item bounding box
     2071#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS)      if (g.TestEngineHookItems) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS)   // Register item label and status flags (optional)
     2072#define IMGUI_TEST_ENGINE_LOG(_FMT,...)                     if (g.TestEngineHookItems) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__)          // Custom log entry from user land into test log
     2073#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA)          if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA));
     2074#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2)  if (g.TestEngineHookIdInfo == id) ImGuiTestEngineHook_IdInfo(&g, _TYPE, _ID, (const void*)(_DATA), (const void*)(_DATA2));
     2075#else
     2076#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB,_ID)                 do { } while (0)
     2077#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID,_LABEL,_FLAGS)      do { } while (0)
     2078#define IMGUI_TEST_ENGINE_LOG(_FMT,...)                     do { } while (0)
     2079#define IMGUI_TEST_ENGINE_ID_INFO(_ID,_TYPE,_DATA)          do { } while (0)
     2080#define IMGUI_TEST_ENGINE_ID_INFO2(_ID,_TYPE,_DATA,_DATA2)  do { } while (0)
     2081#endif
     2082
     2083#if defined(__clang__)
    11452084#pragma clang diagnostic pop
     2085#elif defined(__GNUC__)
     2086#pragma GCC diagnostic pop
    11462087#endif
    11472088
     
    11492090#pragma warning (pop)
    11502091#endif
     2092
     2093#endif // #ifndef IMGUI_DISABLE
  • IMGUI/imstb_rectpack.h

    r78c3045 re66fd66  
    1 // stb_rect_pack.h - v0.11 - public domain - rectangle packing
     1// [DEAR IMGUI]
     2// This is a slightly modified version of stb_rect_pack.h 1.00.
     3// Those changes would need to be pushed into nothings/stb:
     4// - Added STBRP__CDECL
     5// Grep for [DEAR IMGUI] to find the changes.
     6
     7// stb_rect_pack.h - v1.00 - public domain - rectangle packing
    28// Sean Barrett 2014
    39//
     
    3238//  Bugfixes / warning fixes
    3339//    Jeremy Jaussaud
     40//    Fabian Giesen
    3441//
    3542// Version history:
    3643//
     44//     1.00  (2019-02-25)  avoid small space waste; gracefully fail too-wide rectangles
     45//     0.99  (2019-02-07)  warning fixes
    3746//     0.11  (2017-03-03)  return packing success/fail result
    3847//     0.10  (2016-10-25)  remove cast-away-const to avoid warnings
     
    6978#endif
    7079
    71    typedef struct stbrp_context stbrp_context;
    72    typedef struct stbrp_node    stbrp_node;
    73    typedef struct stbrp_rect    stbrp_rect;
     80typedef struct stbrp_context stbrp_context;
     81typedef struct stbrp_node    stbrp_node;
     82typedef struct stbrp_rect    stbrp_rect;
    7483
    7584#ifdef STBRP_LARGE_RECTS
    76    typedef int            stbrp_coord;
     85typedef int            stbrp_coord;
    7786#else
    78    typedef unsigned short stbrp_coord;
    79 #endif
    80 
    81    STBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects);
    82    // Assign packed locations to rectangles. The rectangles are of type
    83    // 'stbrp_rect' defined below, stored in the array 'rects', and there
    84    // are 'num_rects' many of them.
    85    //
    86    // Rectangles which are successfully packed have the 'was_packed' flag
    87    // set to a non-zero value and 'x' and 'y' store the minimum location
    88    // on each axis (i.e. bottom-left in cartesian coordinates, top-left
    89    // if you imagine y increasing downwards). Rectangles which do not fit
    90    // have the 'was_packed' flag set to 0.
    91    //
    92    // You should not try to access the 'rects' array from another thread
    93    // while this function is running, as the function temporarily reorders
    94    // the array while it executes.
    95    //
    96    // To pack into another rectangle, you need to call stbrp_init_target
    97    // again. To continue packing into the same rectangle, you can call
    98    // this function again. Calling this multiple times with multiple rect
    99    // arrays will probably produce worse packing results than calling it
    100    // a single time with the full rectangle array, but the option is
    101    // available.
    102    //
    103    // The function returns 1 if all of the rectangles were successfully
    104    // packed and 0 otherwise.
    105 
    106    struct stbrp_rect
    107    {
    108       // reserved for your use:
    109       int            id;
    110 
    111       // input:
    112       stbrp_coord    w, h;
    113 
    114       // output:
    115       stbrp_coord    x, y;
    116       int            was_packed;  // non-zero if valid packing
    117 
    118    }; // 16 bytes, nominally
    119 
    120 
    121    STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
    122    // Initialize a rectangle packer to:
    123    //    pack a rectangle that is 'width' by 'height' in dimensions
    124    //    using temporary storage provided by the array 'nodes', which is 'num_nodes' long
    125    //
    126    // You must call this function every time you start packing into a new target.
    127    //
    128    // There is no "shutdown" function. The 'nodes' memory must stay valid for
    129    // the following stbrp_pack_rects() call (or calls), but can be freed after
    130    // the call (or calls) finish.
    131    //
    132    // Note: to guarantee best results, either:
    133    //       1. make sure 'num_nodes' >= 'width'
    134    //   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
    135    //
    136    // If you don't do either of the above things, widths will be quantized to multiples
    137    // of small integers to guarantee the algorithm doesn't run out of temporary storage.
    138    //
    139    // If you do #2, then the non-quantized algorithm will be used, but the algorithm
    140    // may run out of temporary storage and be unable to pack some rectangles.
    141 
    142    STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem);
    143    // Optionally call this function after init but before doing any packing to
    144    // change the handling of the out-of-temp-memory scenario, described above.
    145    // If you call init again, this will be reset to the default (false).
    146 
    147 
    148    STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic);
    149    // Optionally select which packing heuristic the library should use. Different
    150    // heuristics will produce better/worse results for different data sets.
    151    // If you call init again, this will be reset to the default.
    152 
    153    enum
    154    {
    155       STBRP_HEURISTIC_Skyline_default = 0,
    156       STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
    157       STBRP_HEURISTIC_Skyline_BF_sortHeight
    158    };
    159 
    160 
    161    //////////////////////////////////////////////////////////////////////////////
    162    //
    163    // the details of the following structures don't matter to you, but they must
    164    // be visible so you can handle the memory allocations for them
    165 
    166    struct stbrp_node
    167    {
    168       stbrp_coord  x, y;
    169       stbrp_node  *next;
    170    };
    171 
    172    struct stbrp_context
    173    {
    174       int width;
    175       int height;
    176       int align;
    177       int init_mode;
    178       int heuristic;
    179       int num_nodes;
    180       stbrp_node *active_head;
    181       stbrp_node *free_head;
    182       stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
    183    };
     87typedef unsigned short stbrp_coord;
     88#endif
     89
     90STBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
     91// Assign packed locations to rectangles. The rectangles are of type
     92// 'stbrp_rect' defined below, stored in the array 'rects', and there
     93// are 'num_rects' many of them.
     94//
     95// Rectangles which are successfully packed have the 'was_packed' flag
     96// set to a non-zero value and 'x' and 'y' store the minimum location
     97// on each axis (i.e. bottom-left in cartesian coordinates, top-left
     98// if you imagine y increasing downwards). Rectangles which do not fit
     99// have the 'was_packed' flag set to 0.
     100//
     101// You should not try to access the 'rects' array from another thread
     102// while this function is running, as the function temporarily reorders
     103// the array while it executes.
     104//
     105// To pack into another rectangle, you need to call stbrp_init_target
     106// again. To continue packing into the same rectangle, you can call
     107// this function again. Calling this multiple times with multiple rect
     108// arrays will probably produce worse packing results than calling it
     109// a single time with the full rectangle array, but the option is
     110// available.
     111//
     112// The function returns 1 if all of the rectangles were successfully
     113// packed and 0 otherwise.
     114
     115struct stbrp_rect
     116{
     117   // reserved for your use:
     118   int            id;
     119
     120   // input:
     121   stbrp_coord    w, h;
     122
     123   // output:
     124   stbrp_coord    x, y;
     125   int            was_packed;  // non-zero if valid packing
     126
     127}; // 16 bytes, nominally
     128
     129
     130STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
     131// Initialize a rectangle packer to:
     132//    pack a rectangle that is 'width' by 'height' in dimensions
     133//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long
     134//
     135// You must call this function every time you start packing into a new target.
     136//
     137// There is no "shutdown" function. The 'nodes' memory must stay valid for
     138// the following stbrp_pack_rects() call (or calls), but can be freed after
     139// the call (or calls) finish.
     140//
     141// Note: to guarantee best results, either:
     142//       1. make sure 'num_nodes' >= 'width'
     143//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
     144//
     145// If you don't do either of the above things, widths will be quantized to multiples
     146// of small integers to guarantee the algorithm doesn't run out of temporary storage.
     147//
     148// If you do #2, then the non-quantized algorithm will be used, but the algorithm
     149// may run out of temporary storage and be unable to pack some rectangles.
     150
     151STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
     152// Optionally call this function after init but before doing any packing to
     153// change the handling of the out-of-temp-memory scenario, described above.
     154// If you call init again, this will be reset to the default (false).
     155
     156
     157STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
     158// Optionally select which packing heuristic the library should use. Different
     159// heuristics will produce better/worse results for different data sets.
     160// If you call init again, this will be reset to the default.
     161
     162enum
     163{
     164   STBRP_HEURISTIC_Skyline_default=0,
     165   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
     166   STBRP_HEURISTIC_Skyline_BF_sortHeight
     167};
     168
     169
     170//////////////////////////////////////////////////////////////////////////////
     171//
     172// the details of the following structures don't matter to you, but they must
     173// be visible so you can handle the memory allocations for them
     174
     175struct stbrp_node
     176{
     177   stbrp_coord  x,y;
     178   stbrp_node  *next;
     179};
     180
     181struct stbrp_context
     182{
     183   int width;
     184   int height;
     185   int align;
     186   int init_mode;
     187   int heuristic;
     188   int num_nodes;
     189   stbrp_node *active_head;
     190   stbrp_node *free_head;
     191   stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
     192};
    184193
    185194#ifdef __cplusplus
     
    205214#endif
    206215
     216// [DEAR IMGUI] Added STBRP__CDECL
    207217#ifdef _MSC_VER
    208218#define STBRP__NOTUSED(v)  (void)(v)
     
    221231{
    222232   switch (context->init_mode) {
    223    case STBRP__INIT_skyline:
    224       STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
    225       context->heuristic = heuristic;
    226       break;
    227    default:
    228       STBRP_ASSERT(0);
     233      case STBRP__INIT_skyline:
     234         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
     235         context->heuristic = heuristic;
     236         break;
     237      default:
     238         STBRP_ASSERT(0);
    229239   }
    230240}
     
    246256      //                  align = ceil(width/num_nodes)
    247257
    248       context->align = (context->width + context->num_nodes - 1) / context->num_nodes;
     258      context->align = (context->width + context->num_nodes-1) / context->num_nodes;
    249259   }
    250260}
     
    257267#endif
    258268
    259    for (i = 0; i < num_nodes - 1; ++i)
    260       nodes[i].next = &nodes[i + 1];
     269   for (i=0; i < num_nodes-1; ++i)
     270      nodes[i].next = &nodes[i+1];
    261271   nodes[i].next = NULL;
    262272   context->init_mode = STBRP__INIT_skyline;
     
    273283   context->extra[0].y = 0;
    274284   context->extra[0].next = &context->extra[1];
    275    context->extra[1].x = (stbrp_coord)width;
     285   context->extra[1].x = (stbrp_coord) width;
    276286#ifdef STBRP_LARGE_RECTS
    277    context->extra[1].y = (1 << 30);
     287   context->extra[1].y = (1<<30);
    278288#else
    279289   context->extra[1].y = 65535;
     
    293303   STBRP_ASSERT(first->x <= x0);
    294304
    295 #if 0
     305   #if 0
    296306   // skip in case we're past the node
    297307   while (node->next->x <= x0)
    298308      ++node;
    299 #else
     309   #else
    300310   STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
    301 #endif
     311   #endif
    302312
    303313   STBRP_ASSERT(node->x <= x0);
     
    318328         else
    319329            visited_width += node->next->x - node->x;
    320       }
    321       else {
     330      } else {
    322331         // add waste area
    323332         int under_width = node->next->x - node->x;
     
    336345typedef struct
    337346{
    338    int x, y;
     347   int x,y;
    339348   stbrp_node **prev_link;
    340349} stbrp__findresult;
     
    342351static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
    343352{
    344    int best_waste = (1 << 30), best_x, best_y = (1 << 30);
     353   int best_waste = (1<<30), best_x, best_y = (1 << 30);
    345354   stbrp__findresult fr;
    346355   stbrp_node **prev, *node, *tail, **best = NULL;
     
    351360   STBRP_ASSERT(width % c->align == 0);
    352361
     362   // if it can't possibly fit, bail immediately
     363   if (width > c->width || height > c->height) {
     364      fr.prev_link = NULL;
     365      fr.x = fr.y = 0;
     366      return fr;
     367   }
     368
    353369   node = c->active_head;
    354370   prev = &c->active_head;
    355371   while (node->x + width <= c->width) {
    356       int y, waste;
     372      int y,waste;
    357373      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
    358374      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
    359                                                                    // bottom left
     375         // bottom left
    360376         if (y < best_y) {
    361377            best_y = y;
    362378            best = prev;
    363379         }
    364       }
    365       else {
     380      } else {
    366381         // best-fit
    367382         if (y + height <= c->height) {
     
    406421      while (tail) {
    407422         int xpos = tail->x - width;
    408          int y, waste;
     423         int y,waste;
    409424         STBRP_ASSERT(xpos >= 0);
    410425         // find the left position that matches this
     
    415430         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
    416431         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
    417          if (y + height < c->height) {
     432         if (y + height <= c->height) {
    418433            if (y <= best_y) {
    419                if (y < best_y || waste < best_waste || (waste == best_waste && xpos < best_x)) {
     434               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
    420435                  best_x = xpos;
    421436                  STBRP_ASSERT(y <= best_y);
     
    427442         }
    428443         tail = tail->next;
    429       }
     444      }         
    430445   }
    431446
     
    453468   // on success, create new node
    454469   node = context->free_head;
    455    node->x = (stbrp_coord)res.x;
    456    node->y = (stbrp_coord)(res.y + height);
     470   node->x = (stbrp_coord) res.x;
     471   node->y = (stbrp_coord) (res.y + height);
    457472
    458473   context->free_head = node->next;
     
    468483      cur->next = node;
    469484      cur = next;
    470    }
    471    else {
     485   } else {
    472486      *res.prev_link = node;
    473487   }
     
    487501
    488502   if (cur->x < res.x + width)
    489       cur->x = (stbrp_coord)(res.x + width);
     503      cur->x = (stbrp_coord) (res.x + width);
    490504
    491505#ifdef _DEBUG
     
    498512
    499513   {
    500       int count = 0;
     514      int count=0;
    501515      cur = context->active_head;
    502516      while (cur) {
     
    509523         ++count;
    510524      }
    511       STBRP_ASSERT(count == context->num_nodes + 2);
     525      STBRP_ASSERT(count == context->num_nodes+2);
    512526   }
    513527#endif
     
    516530}
    517531
     532// [DEAR IMGUI] Added STBRP__CDECL
    518533static int STBRP__CDECL rect_height_compare(const void *a, const void *b)
    519534{
    520    const stbrp_rect *p = (const stbrp_rect *)a;
    521    const stbrp_rect *q = (const stbrp_rect *)b;
     535   const stbrp_rect *p = (const stbrp_rect *) a;
     536   const stbrp_rect *q = (const stbrp_rect *) b;
    522537   if (p->h > q->h)
    523538      return -1;
     
    527542}
    528543
     544// [DEAR IMGUI] Added STBRP__CDECL
    529545static int STBRP__CDECL rect_original_order(const void *a, const void *b)
    530546{
    531    const stbrp_rect *p = (const stbrp_rect *)a;
    532    const stbrp_rect *q = (const stbrp_rect *)b;
     547   const stbrp_rect *p = (const stbrp_rect *) a;
     548   const stbrp_rect *q = (const stbrp_rect *) b;
    533549   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
    534550}
     
    545561
    546562   // we use the 'was_packed' field internally to allow sorting/unsorting
    547    for (i = 0; i < num_rects; ++i) {
     563   for (i=0; i < num_rects; ++i) {
    548564      rects[i].was_packed = i;
    549 #ifndef STBRP_LARGE_RECTS
    550       STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
    551 #endif
    552565   }
    553566
     
    555568   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
    556569
    557    for (i = 0; i < num_rects; ++i) {
     570   for (i=0; i < num_rects; ++i) {
    558571      if (rects[i].w == 0 || rects[i].h == 0) {
    559572         rects[i].x = rects[i].y = 0;  // empty rect needs no space
    560       }
    561       else {
     573      } else {
    562574         stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
    563575         if (fr.prev_link) {
    564             rects[i].x = (stbrp_coord)fr.x;
    565             rects[i].y = (stbrp_coord)fr.y;
    566          }
    567          else {
     576            rects[i].x = (stbrp_coord) fr.x;
     577            rects[i].y = (stbrp_coord) fr.y;
     578         } else {
    568579            rects[i].x = rects[i].y = STBRP__MAXVAL;
    569580         }
     
    575586
    576587   // set was_packed flags and all_rects_packed status
    577    for (i = 0; i < num_rects; ++i) {
     588   for (i=0; i < num_rects; ++i) {
    578589      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
    579590      if (!rects[i].was_packed)
     
    592603ALTERNATIVE A - MIT License
    593604Copyright (c) 2017 Sean Barrett
    594 Permission is hereby granted, free of charge, to any person obtaining a copy of
    595 this software and associated documentation files (the "Software"), to deal in
    596 the Software without restriction, including without limitation the rights to
    597 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
    598 of the Software, and to permit persons to whom the Software is furnished to do
     605Permission is hereby granted, free of charge, to any person obtaining a copy of 
     606this software and associated documentation files (the "Software"), to deal in 
     607the Software without restriction, including without limitation the rights to 
     608use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
     609of the Software, and to permit persons to whom the Software is furnished to do 
    599610so, subject to the following conditions:
    600 The above copyright notice and this permission notice shall be included in all
     611The above copyright notice and this permission notice shall be included in all 
    601612copies or substantial portions of the Software.
    602 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    603 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    604 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    605 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    606 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    607 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     613THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
     614IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
     615FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
     616AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
     617LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
     618OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
    608619SOFTWARE.
    609620------------------------------------------------------------------------------
    610621ALTERNATIVE B - Public Domain (www.unlicense.org)
    611622This is free and unencumbered software released into the public domain.
    612 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
    613 software, either in source code form or as a compiled binary, for any purpose,
     623Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 
     624software, either in source code form or as a compiled binary, for any purpose, 
    614625commercial or non-commercial, and by any means.
    615 In jurisdictions that recognize copyright laws, the author or authors of this
    616 software dedicate any and all copyright interest in the software to the public
    617 domain. We make this dedication for the benefit of the public at large and to
    618 the detriment of our heirs and successors. We intend this dedication to be an
    619 overt act of relinquishment in perpetuity of all present and future rights to
     626In jurisdictions that recognize copyright laws, the author or authors of this 
     627software dedicate any and all copyright interest in the software to the public 
     628domain. We make this dedication for the benefit of the public at large and to 
     629the detriment of our heirs and successors. We intend this dedication to be an 
     630overt act of relinquishment in perpetuity of all present and future rights to 
    620631this software under copyright law.
    621 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    622 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    623 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    624 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
    625 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     632THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
     633IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
     634FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
     635AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
     636ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    626637WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    627638------------------------------------------------------------------------------
  • IMGUI/imstb_textedit.h

    r78c3045 re66fd66  
    1 // [ImGui] this is a slightly modified version of stb_truetype.h 1.9. Those changes would need to be pushed into nothings/sb
    2 // [ImGui] - fixed linestart handler when over last character of multi-line buffer + simplified existing code (#588, #815)
    3 // [ImGui] - fixed a state corruption/crash bug in stb_text_redo and stb_textedit_discard_redo (#715)
    4 // [ImGui] - fixed a crash bug in stb_textedit_discard_redo (#681)
    5 // [ImGui] - fixed some minor warnings
    6 
    7 // stb_textedit.h - v1.9  - public domain - Sean Barrett
     1// [DEAR IMGUI]
     2// This is a slightly modified version of stb_textedit.h 1.13.
     3// Those changes would need to be pushed into nothings/stb:
     4// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
     5// Grep for [DEAR IMGUI] to find the changes.
     6
     7// stb_textedit.h - v1.13  - public domain - Sean Barrett
    88// Development of this library was sponsored by RAD Game Tools
    99//
     
    2424// LICENSE
    2525//
    26 //   This software is dual-licensed to the public domain and under the following
    27 //   license: you are granted a perpetual, irrevocable license to copy, modify,
    28 //   publish, and distribute this file as you see fit.
     26// See end of file for license information.
    2927//
    3028//
     
    3836// VERSION HISTORY
    3937//
     38//   1.13 (2019-02-07) fix bug in undo size management
     39//   1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
     40//   1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
     41//   1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
    4042//   1.9  (2016-08-27) customizable move-by-word
    4143//   1.8  (2016-04-02) better keyboard handling when mouse button is down
     
    5658//   Ulf Winklemann: move-by-word in 1.1
    5759//   Fabian Giesen: secondary key inputs in 1.5
    58 //   Martins Mozeiko: STB_TEXTEDIT_memmove
     60//   Martins Mozeiko: STB_TEXTEDIT_memmove in 1.6
    5961//
    6062//   Bugfixes:
     
    6264//      Daniel Keller
    6365//      Omar Cornut
     66//      Dan Thompson
    6467//
    6568// USAGE
     
    9194//   it grows STB_TexteditState by the worst-case storage which is (in bytes):
    9295//
    93 //        [4 + sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT
    94 //      +      sizeof(STB_TEXTEDIT_CHARTYPE)      * STB_TEXTEDIT_UNDOCHAR_COUNT
     96//        [4 + 3 * sizeof(STB_TEXTEDIT_POSITIONTYPE)] * STB_TEXTEDIT_UNDOSTATE_COUNT
     97//      +          sizeof(STB_TEXTEDIT_CHARTYPE)      * STB_TEXTEDIT_UNDOCHAR_COUNT
    9598//
    9699//
     
    115118//
    116119//     STB_TEXTEDIT_CHARTYPE             the character type
    117 //     STB_TEXTEDIT_POSITIONTYPE         small type that a valid cursor position
     120//     STB_TEXTEDIT_POSITIONTYPE         small type that is a valid cursor position
    118121//     STB_TEXTEDIT_UNDOSTATECOUNT       the number of undo states to allow
    119122//     STB_TEXTEDIT_UNDOCHARCOUNT        the number of characters to store in the undo buffer
     
    146149//    STB_TEXTEDIT_K_UP          keyboard input to move cursor up
    147150//    STB_TEXTEDIT_K_DOWN        keyboard input to move cursor down
     151//    STB_TEXTEDIT_K_PGUP        keyboard input to move cursor up a page
     152//    STB_TEXTEDIT_K_PGDOWN      keyboard input to move cursor down a page
    148153//    STB_TEXTEDIT_K_LINESTART   keyboard input to move cursor to start of line  // e.g. HOME
    149154//    STB_TEXTEDIT_K_LINEEND     keyboard input to move cursor to end of line    // e.g. END
     
    168173//    STB_TEXTEDIT_K_TEXTEND2            secondary keyboard input to move cursor to end of text
    169174//
    170 // Todo:
    171 //    STB_TEXTEDIT_K_PGUP        keyboard input to move cursor up a page
    172 //    STB_TEXTEDIT_K_PGDOWN      keyboard input to move cursor down a page
    173 //
    174175// Keyboard input must be encoded as a single integer value; e.g. a character code
    175176// and some bitflags that represent shift states. to simplify the interface, SHIFT must
    176177// be a bitflag, so we can test the shifted state of cursor movements to allow selection,
    177 // i.e. (STB_TEXTED_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.
     178// i.e. (STB_TEXTEDIT_K_RIGHT|STB_TEXTEDIT_K_SHIFT) should be shifted right-arrow.
    178179//
    179180// You can encode other things, such as CONTROL or ALT, in additional bits, and
     
    204205//    int  stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
    205206//    int  stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
    206 //    void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key)
     207//    void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
    207208//
    208209//    Each of these functions potentially updates the string and updates the
     
    238239//          various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
    239240//          set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
    240 //          clear.
     241//          clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
     242//          anything other type you wante before including.
     243//
    241244//     
    242245//   When rendering, you can read the cursor position and selection state from
     
    298301   // private data
    299302   STB_TEXTEDIT_POSITIONTYPE  where;
    300    short           insert_length;
    301    short           delete_length;
    302    short           char_storage;
     303   STB_TEXTEDIT_POSITIONTYPE  insert_length;
     304   STB_TEXTEDIT_POSITIONTYPE  delete_length;
     305   int                        char_storage;
    303306} StbUndoRecord;
    304307
     
    306309{
    307310   // private data
    308    StbUndoRecord          undo_rec[STB_TEXTEDIT_UNDOSTATECOUNT];
     311   StbUndoRecord          undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT];
    309312   STB_TEXTEDIT_CHARTYPE  undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
    310313   short undo_point, redo_point;
    311    short undo_char_point, redo_char_point;
     314   int undo_char_point, redo_char_point;
    312315} StbUndoState;
    313316
     
    332335   // each textfield keeps its own insert mode state. to keep an app-wide
    333336   // insert mode, copy this value in/out of the app state
     337
     338   int row_count_per_page;
     339   // page size in number of row.
     340   // this value MUST be set to >0 for pageup or pagedown in multilines documents.
    334341
    335342   /////////////////////
     
    357364typedef struct
    358365{
    359    float x0, x1;             // starting x location, end x location (allows for align=right, etc)
     366   float x0,x1;             // starting x location, end x location (allows for align=right, etc)
    360367   float baseline_y_delta;  // position of baseline relative to previous row's baseline
    361    float ymin, ymax;         // height of row above and below baseline
     368   float ymin,ymax;         // height of row above and below baseline
    362369   int num_chars;
    363370} StbTexteditRow;
     
    394401   int n = STB_TEXTEDIT_STRINGLEN(str);
    395402   float base_y = 0, prev_x;
    396    int i = 0, k;
     403   int i=0, k;
    397404
    398405   r.x0 = r.x1 = 0;
     
    406413         return n;
    407414
    408       if (i == 0 && y < base_y + r.ymin)
     415      if (i==0 && y < base_y + r.ymin)
    409416         return 0;
    410417
     
    428435      // search characters in row for one that straddles 'x'
    429436      prev_x = r.x0;
    430       for (k = 0; k < r.num_chars; ++k) {
     437      for (k=0; k < r.num_chars; ++k) {
    431438         float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
    432          if (x < prev_x + w) {
    433             if (x < prev_x + w / 2)
    434                return k + i;
     439         if (x < prev_x+w) {
     440            if (x < prev_x+w/2)
     441               return k+i;
    435442            else
    436                return k + i + 1;
     443               return k+i+1;
    437444         }
    438445         prev_x += w;
     
    442449
    443450   // if the last character is a newline, return that. otherwise return 'after' the last character
    444    if (STB_TEXTEDIT_GETCHAR(str, i + r.num_chars - 1) == STB_TEXTEDIT_NEWLINE)
    445       return i + r.num_chars - 1;
     451   if (STB_TEXTEDIT_GETCHAR(str, i+r.num_chars-1) == STB_TEXTEDIT_NEWLINE)
     452      return i+r.num_chars-1;
    446453   else
    447       return i + r.num_chars;
     454      return i+r.num_chars;
    448455}
    449456
     
    451458static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
    452459{
     460   // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
     461   // goes off the top or bottom of the text
     462   if( state->single_line )
     463   {
     464      StbTexteditRow r;
     465      STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
     466      y = r.ymin;
     467   }
     468
    453469   state->cursor = stb_text_locate_coord(str, x, y);
    454470   state->select_start = state->cursor;
     
    460476static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
    461477{
    462    int p = stb_text_locate_coord(str, x, y);
     478   int p = 0;
     479
     480   // In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
     481   // goes off the top or bottom of the text
     482   if( state->single_line )
     483   {
     484      StbTexteditRow r;
     485      STB_TEXTEDIT_LAYOUTROW(&r, str, 0);
     486      y = r.ymin;
     487   }
     488
    463489   if (state->select_start == state->select_end)
    464490      state->select_start = state->cursor;
     491
     492   p = stb_text_locate_coord(str, x, y);
    465493   state->cursor = state->select_end = p;
    466494}
     
    480508typedef struct
    481509{
    482    float x, y;    // position of n'th character
     510   float x,y;    // position of n'th character
    483511   float height; // height of line
    484512   int first_char, length; // first char of row, and length
     
    493521   int prev_start = 0;
    494522   int z = STB_TEXTEDIT_STRINGLEN(str);
    495    int i = 0, first;
     523   int i=0, first;
    496524
    497525   if (n == z) {
     
    505533         find->height = r.ymax - r.ymin;
    506534         find->x = r.x1;
    507       }
    508       else {
     535      } else {
    509536         find->y = 0;
    510537         find->x = 0;
     
    525552   find->y = 0;
    526553
    527    for (;;) {
     554   for(;;) {
    528555      STB_TEXTEDIT_LAYOUTROW(&r, str, i);
    529556      if (n < i + r.num_chars)
     
    541568   // now scan to find xpos
    542569   find->x = r.x0;
    543    i = 0;
    544    for (i = 0; first + i < n; ++i)
     570   for (i=0; first+i < n; ++i)
    545571      find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
    546572}
     
    578604         stb_textedit_delete(str, state, state->select_start, state->select_end - state->select_start);
    579605         state->select_end = state->cursor = state->select_start;
    580       }
    581       else {
     606      } else {
    582607         stb_textedit_delete(str, state, state->select_end, state->select_start - state->select_end);
    583608         state->select_start = state->cursor = state->select_end;
     
    621646
    622647#ifdef STB_TEXTEDIT_IS_SPACE
    623 static int is_word_boundary(STB_TEXTEDIT_STRING *str, int idx)
    624 {
    625    return idx > 0 ? (STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx - 1)) && !STB_TEXTEDIT_IS_SPACE(STB_TEXTEDIT_GETCHAR(str, idx))) : 1;
     648static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx )
     649{
     650   return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
    626651}
    627652
    628653#ifndef STB_TEXTEDIT_MOVEWORDLEFT
    629 static int stb_textedit_move_to_word_previous(STB_TEXTEDIT_STRING *str, int c)
     654static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
    630655{
    631656   --c; // always move at least one character
    632    while (c >= 0 && !is_word_boundary(str, c))
     657   while( c >= 0 && !is_word_boundary( str, c ) )
    633658      --c;
    634659
    635    if (c < 0)
     660   if( c < 0 )
    636661      c = 0;
    637662
     
    642667
    643668#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
    644 static int stb_textedit_move_to_word_next(STB_TEXTEDIT_STRING *str, int c)
     669static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c )
    645670{
    646671   const int len = STB_TEXTEDIT_STRINGLEN(str);
    647672   ++c; // always move at least one character
    648    while (c < len && !is_word_boundary(str, c))
     673   while( c < len && !is_word_boundary( str, c ) )
    649674      ++c;
    650675
    651    if (c > len)
     676   if( c > len )
    652677      c = len;
    653678
     
    672697{
    673698   if (STB_TEXT_HAS_SELECTION(state)) {
    674       stb_textedit_delete_selection(str, state); // implicity clamps
     699      stb_textedit_delete_selection(str,state); // implicitly clamps
    675700      state->has_preferred_x = 0;
    676701      return 1;
     
    680705
    681706// API paste: replace existing selection with passed-in text
    682 static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *text, int len)
     707static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
    683708{
    684709   // if there's a selection, the paste should delete it
    685710   stb_textedit_clamp(str, state);
    686    stb_textedit_delete_selection(str, state);
     711   stb_textedit_delete_selection(str,state);
    687712   // try to insert the characters
    688713   if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, len)) {
     
    698723}
    699724
     725#ifndef STB_TEXTEDIT_KEYTYPE
     726#define STB_TEXTEDIT_KEYTYPE int
     727#endif
     728
    700729// API key: process a keyboard input
    701 static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key)
     730static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
    702731{
    703732retry:
    704733   switch (key) {
    705    default: {
    706       int c = STB_TEXTEDIT_KEYTOTEXT(key);
    707       if (c > 0) {
    708          STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE)c;
    709 
    710          // can't add newline in single-line mode
    711          if (c == '\n' && state->single_line)
    712             break;
    713 
    714          if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
    715             stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
    716             STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
    717             if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
    718                ++state->cursor;
    719                state->has_preferred_x = 0;
     734      default: {
     735         int c = STB_TEXTEDIT_KEYTOTEXT(key);
     736         if (c > 0) {
     737            STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c;
     738
     739            // can't add newline in single-line mode
     740            if (c == '\n' && state->single_line)
     741               break;
     742
     743            if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
     744               stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
     745               STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
     746               if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
     747                  ++state->cursor;
     748                  state->has_preferred_x = 0;
     749               }
     750            } else {
     751               stb_textedit_delete_selection(str,state); // implicitly clamps
     752               if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
     753                  stb_text_makeundo_insert(state, state->cursor, 1);
     754                  ++state->cursor;
     755                  state->has_preferred_x = 0;
     756               }
    720757            }
    721758         }
     759         break;
     760      }
     761
     762#ifdef STB_TEXTEDIT_K_INSERT
     763      case STB_TEXTEDIT_K_INSERT:
     764         state->insert_mode = !state->insert_mode;
     765         break;
     766#endif
     767         
     768      case STB_TEXTEDIT_K_UNDO:
     769         stb_text_undo(str, state);
     770         state->has_preferred_x = 0;
     771         break;
     772
     773      case STB_TEXTEDIT_K_REDO:
     774         stb_text_redo(str, state);
     775         state->has_preferred_x = 0;
     776         break;
     777
     778      case STB_TEXTEDIT_K_LEFT:
     779         // if currently there's a selection, move cursor to start of selection
     780         if (STB_TEXT_HAS_SELECTION(state))
     781            stb_textedit_move_to_first(state);
     782         else
     783            if (state->cursor > 0)
     784               --state->cursor;
     785         state->has_preferred_x = 0;
     786         break;
     787
     788      case STB_TEXTEDIT_K_RIGHT:
     789         // if currently there's a selection, move cursor to end of selection
     790         if (STB_TEXT_HAS_SELECTION(state))
     791            stb_textedit_move_to_last(str, state);
     792         else
     793            ++state->cursor;
     794         stb_textedit_clamp(str, state);
     795         state->has_preferred_x = 0;
     796         break;
     797
     798      case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
     799         stb_textedit_clamp(str, state);
     800         stb_textedit_prep_selection_at_cursor(state);
     801         // move selection left
     802         if (state->select_end > 0)
     803            --state->select_end;
     804         state->cursor = state->select_end;
     805         state->has_preferred_x = 0;
     806         break;
     807
     808#ifdef STB_TEXTEDIT_MOVEWORDLEFT
     809      case STB_TEXTEDIT_K_WORDLEFT:
     810         if (STB_TEXT_HAS_SELECTION(state))
     811            stb_textedit_move_to_first(state);
    722812         else {
    723             stb_textedit_delete_selection(str, state); // implicity clamps
    724             if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
    725                stb_text_makeundo_insert(state, state->cursor, 1);
     813            state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
     814            stb_textedit_clamp( str, state );
     815         }
     816         break;
     817
     818      case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:
     819         if( !STB_TEXT_HAS_SELECTION( state ) )
     820            stb_textedit_prep_selection_at_cursor(state);
     821
     822         state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
     823         state->select_end = state->cursor;
     824
     825         stb_textedit_clamp( str, state );
     826         break;
     827#endif
     828
     829#ifdef STB_TEXTEDIT_MOVEWORDRIGHT
     830      case STB_TEXTEDIT_K_WORDRIGHT:
     831         if (STB_TEXT_HAS_SELECTION(state))
     832            stb_textedit_move_to_last(str, state);
     833         else {
     834            state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
     835            stb_textedit_clamp( str, state );
     836         }
     837         break;
     838
     839      case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
     840         if( !STB_TEXT_HAS_SELECTION( state ) )
     841            stb_textedit_prep_selection_at_cursor(state);
     842
     843         state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
     844         state->select_end = state->cursor;
     845
     846         stb_textedit_clamp( str, state );
     847         break;
     848#endif
     849
     850      case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
     851         stb_textedit_prep_selection_at_cursor(state);
     852         // move selection right
     853         ++state->select_end;
     854         stb_textedit_clamp(str, state);
     855         state->cursor = state->select_end;
     856         state->has_preferred_x = 0;
     857         break;
     858
     859      case STB_TEXTEDIT_K_DOWN:
     860      case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT:
     861      case STB_TEXTEDIT_K_PGDOWN:
     862      case STB_TEXTEDIT_K_PGDOWN | STB_TEXTEDIT_K_SHIFT: {
     863         StbFindState find;
     864         StbTexteditRow row;
     865         int i, j, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
     866         int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGDOWN;
     867         int row_count = is_page ? state->row_count_per_page : 1;
     868
     869         if (!is_page && state->single_line) {
     870            // on windows, up&down in single-line behave like left&right
     871            key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
     872            goto retry;
     873         }
     874
     875         if (sel)
     876            stb_textedit_prep_selection_at_cursor(state);
     877         else if (STB_TEXT_HAS_SELECTION(state))
     878            stb_textedit_move_to_last(str, state);
     879
     880         // compute current position of cursor point
     881         stb_textedit_clamp(str, state);
     882         stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
     883
     884         for (j = 0; j < row_count; ++j) {
     885            float x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
     886            int start = find.first_char + find.length;
     887
     888            if (find.length == 0)
     889               break;
     890
     891            // [DEAR IMGUI]
     892            // going down while being on the last line shouldn't bring us to that line end
     893            if (STB_TEXTEDIT_GETCHAR(str, find.first_char + find.length - 1) != STB_TEXTEDIT_NEWLINE)
     894               break;
     895
     896            // now find character position down a row
     897            state->cursor = start;
     898            STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
     899            x = row.x0;
     900            for (i=0; i < row.num_chars; ++i) {
     901               float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
     902               #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
     903               if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
     904                  break;
     905               #endif
     906               x += dx;
     907               if (x > goal_x)
     908                  break;
    726909               ++state->cursor;
    727                state->has_preferred_x = 0;
     910            }
     911            stb_textedit_clamp(str, state);
     912
     913            state->has_preferred_x = 1;
     914            state->preferred_x = goal_x;
     915
     916            if (sel)
     917               state->select_end = state->cursor;
     918
     919            // go to next line
     920            find.first_char = find.first_char + find.length;
     921            find.length = row.num_chars;
     922         }
     923         break;
     924      }
     925         
     926      case STB_TEXTEDIT_K_UP:
     927      case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT:
     928      case STB_TEXTEDIT_K_PGUP:
     929      case STB_TEXTEDIT_K_PGUP | STB_TEXTEDIT_K_SHIFT: {
     930         StbFindState find;
     931         StbTexteditRow row;
     932         int i, j, prev_scan, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
     933         int is_page = (key & ~STB_TEXTEDIT_K_SHIFT) == STB_TEXTEDIT_K_PGUP;
     934         int row_count = is_page ? state->row_count_per_page : 1;
     935
     936         if (!is_page && state->single_line) {
     937            // on windows, up&down become left&right
     938            key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
     939            goto retry;
     940         }
     941
     942         if (sel)
     943            stb_textedit_prep_selection_at_cursor(state);
     944         else if (STB_TEXT_HAS_SELECTION(state))
     945            stb_textedit_move_to_first(state);
     946
     947         // compute current position of cursor point
     948         stb_textedit_clamp(str, state);
     949         stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
     950
     951         for (j = 0; j < row_count; ++j) {
     952            float  x, goal_x = state->has_preferred_x ? state->preferred_x : find.x;
     953
     954            // can only go up if there's a previous row
     955            if (find.prev_first == find.first_char)
     956               break;
     957
     958            // now find character position up a row
     959            state->cursor = find.prev_first;
     960            STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
     961            x = row.x0;
     962            for (i=0; i < row.num_chars; ++i) {
     963               float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
     964               #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
     965               if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
     966                  break;
     967               #endif
     968               x += dx;
     969               if (x > goal_x)
     970                  break;
     971               ++state->cursor;
     972            }
     973            stb_textedit_clamp(str, state);
     974
     975            state->has_preferred_x = 1;
     976            state->preferred_x = goal_x;
     977
     978            if (sel)
     979               state->select_end = state->cursor;
     980
     981            // go to previous line
     982            // (we need to scan previous line the hard way. maybe we could expose this as a new API function?)
     983            prev_scan = find.prev_first > 0 ? find.prev_first - 1 : 0;
     984            while (prev_scan > 0 && STB_TEXTEDIT_GETCHAR(str, prev_scan - 1) != STB_TEXTEDIT_NEWLINE)
     985               --prev_scan;
     986            find.first_char = find.prev_first;
     987            find.prev_first = prev_scan;
     988         }
     989         break;
     990      }
     991
     992      case STB_TEXTEDIT_K_DELETE:
     993      case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:
     994         if (STB_TEXT_HAS_SELECTION(state))
     995            stb_textedit_delete_selection(str, state);
     996         else {
     997            int n = STB_TEXTEDIT_STRINGLEN(str);
     998            if (state->cursor < n)
     999               stb_textedit_delete(str, state, state->cursor, 1);
     1000         }
     1001         state->has_preferred_x = 0;
     1002         break;
     1003
     1004      case STB_TEXTEDIT_K_BACKSPACE:
     1005      case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:
     1006         if (STB_TEXT_HAS_SELECTION(state))
     1007            stb_textedit_delete_selection(str, state);
     1008         else {
     1009            stb_textedit_clamp(str, state);
     1010            if (state->cursor > 0) {
     1011               stb_textedit_delete(str, state, state->cursor-1, 1);
     1012               --state->cursor;
    7281013            }
    7291014         }
     1015         state->has_preferred_x = 0;
     1016         break;
     1017         
     1018#ifdef STB_TEXTEDIT_K_TEXTSTART2
     1019      case STB_TEXTEDIT_K_TEXTSTART2:
     1020#endif
     1021      case STB_TEXTEDIT_K_TEXTSTART:
     1022         state->cursor = state->select_start = state->select_end = 0;
     1023         state->has_preferred_x = 0;
     1024         break;
     1025
     1026#ifdef STB_TEXTEDIT_K_TEXTEND2
     1027      case STB_TEXTEDIT_K_TEXTEND2:
     1028#endif
     1029      case STB_TEXTEDIT_K_TEXTEND:
     1030         state->cursor = STB_TEXTEDIT_STRINGLEN(str);
     1031         state->select_start = state->select_end = 0;
     1032         state->has_preferred_x = 0;
     1033         break;
     1034       
     1035#ifdef STB_TEXTEDIT_K_TEXTSTART2
     1036      case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
     1037#endif
     1038      case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
     1039         stb_textedit_prep_selection_at_cursor(state);
     1040         state->cursor = state->select_end = 0;
     1041         state->has_preferred_x = 0;
     1042         break;
     1043
     1044#ifdef STB_TEXTEDIT_K_TEXTEND2
     1045      case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:
     1046#endif
     1047      case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
     1048         stb_textedit_prep_selection_at_cursor(state);
     1049         state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
     1050         state->has_preferred_x = 0;
     1051         break;
     1052
     1053
     1054#ifdef STB_TEXTEDIT_K_LINESTART2
     1055      case STB_TEXTEDIT_K_LINESTART2:
     1056#endif
     1057      case STB_TEXTEDIT_K_LINESTART:
     1058         stb_textedit_clamp(str, state);
     1059         stb_textedit_move_to_first(state);
     1060         if (state->single_line)
     1061            state->cursor = 0;
     1062         else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
     1063            --state->cursor;
     1064         state->has_preferred_x = 0;
     1065         break;
     1066
     1067#ifdef STB_TEXTEDIT_K_LINEEND2
     1068      case STB_TEXTEDIT_K_LINEEND2:
     1069#endif
     1070      case STB_TEXTEDIT_K_LINEEND: {
     1071         int n = STB_TEXTEDIT_STRINGLEN(str);
     1072         stb_textedit_clamp(str, state);
     1073         stb_textedit_move_to_first(state);
     1074         if (state->single_line)
     1075             state->cursor = n;
     1076         else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
     1077             ++state->cursor;
     1078         state->has_preferred_x = 0;
     1079         break;
    7301080      }
    731       break;
    732    }
    733 
    734 #ifdef STB_TEXTEDIT_K_INSERT
    735    case STB_TEXTEDIT_K_INSERT:
    736       state->insert_mode = !state->insert_mode;
    737       break;
    738 #endif
    739 
    740    case STB_TEXTEDIT_K_UNDO:
    741       stb_text_undo(str, state);
    742       state->has_preferred_x = 0;
    743       break;
    744 
    745    case STB_TEXTEDIT_K_REDO:
    746       stb_text_redo(str, state);
    747       state->has_preferred_x = 0;
    748       break;
    749 
    750    case STB_TEXTEDIT_K_LEFT:
    751       // if currently there's a selection, move cursor to start of selection
    752       if (STB_TEXT_HAS_SELECTION(state))
    753          stb_textedit_move_to_first(state);
    754       else
    755          if (state->cursor > 0)
     1081
     1082#ifdef STB_TEXTEDIT_K_LINESTART2
     1083      case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
     1084#endif
     1085      case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
     1086         stb_textedit_clamp(str, state);
     1087         stb_textedit_prep_selection_at_cursor(state);
     1088         if (state->single_line)
     1089            state->cursor = 0;
     1090         else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor-1) != STB_TEXTEDIT_NEWLINE)
    7561091            --state->cursor;
    757       state->has_preferred_x = 0;
    758       break;
    759 
    760    case STB_TEXTEDIT_K_RIGHT:
    761       // if currently there's a selection, move cursor to end of selection
    762       if (STB_TEXT_HAS_SELECTION(state))
    763          stb_textedit_move_to_last(str, state);
    764       else
    765          ++state->cursor;
    766       stb_textedit_clamp(str, state);
    767       state->has_preferred_x = 0;
    768       break;
    769 
    770    case STB_TEXTEDIT_K_LEFT | STB_TEXTEDIT_K_SHIFT:
    771       stb_textedit_clamp(str, state);
    772       stb_textedit_prep_selection_at_cursor(state);
    773       // move selection left
    774       if (state->select_end > 0)
    775          --state->select_end;
    776       state->cursor = state->select_end;
    777       state->has_preferred_x = 0;
    778       break;
    779 
    780 #ifdef STB_TEXTEDIT_MOVEWORDLEFT
    781    case STB_TEXTEDIT_K_WORDLEFT:
    782       if (STB_TEXT_HAS_SELECTION(state))
    783          stb_textedit_move_to_first(state);
    784       else {
    785          state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
     1092         state->select_end = state->cursor;
     1093         state->has_preferred_x = 0;
     1094         break;
     1095
     1096#ifdef STB_TEXTEDIT_K_LINEEND2
     1097      case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
     1098#endif
     1099      case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
     1100         int n = STB_TEXTEDIT_STRINGLEN(str);
    7861101         stb_textedit_clamp(str, state);
     1102         stb_textedit_prep_selection_at_cursor(state);
     1103         if (state->single_line)
     1104             state->cursor = n;
     1105         else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
     1106            ++state->cursor;
     1107         state->select_end = state->cursor;
     1108         state->has_preferred_x = 0;
     1109         break;
    7871110      }
    788       break;
    789 
    790    case STB_TEXTEDIT_K_WORDLEFT | STB_TEXTEDIT_K_SHIFT:
    791       if (!STB_TEXT_HAS_SELECTION(state))
    792          stb_textedit_prep_selection_at_cursor(state);
    793 
    794       state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor);
    795       state->select_end = state->cursor;
    796 
    797       stb_textedit_clamp(str, state);
    798       break;
    799 #endif
    800 
    801 #ifdef STB_TEXTEDIT_MOVEWORDRIGHT
    802    case STB_TEXTEDIT_K_WORDRIGHT:
    803       if (STB_TEXT_HAS_SELECTION(state))
    804          stb_textedit_move_to_last(str, state);
    805       else {
    806          state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
    807          stb_textedit_clamp(str, state);
    808       }
    809       break;
    810 
    811    case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT:
    812       if (!STB_TEXT_HAS_SELECTION(state))
    813          stb_textedit_prep_selection_at_cursor(state);
    814 
    815       state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor);
    816       state->select_end = state->cursor;
    817 
    818       stb_textedit_clamp(str, state);
    819       break;
    820 #endif
    821 
    822    case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
    823       stb_textedit_prep_selection_at_cursor(state);
    824       // move selection right
    825       ++state->select_end;
    826       stb_textedit_clamp(str, state);
    827       state->cursor = state->select_end;
    828       state->has_preferred_x = 0;
    829       break;
    830 
    831    case STB_TEXTEDIT_K_DOWN:
    832    case STB_TEXTEDIT_K_DOWN | STB_TEXTEDIT_K_SHIFT: {
    833       StbFindState find;
    834       StbTexteditRow row;
    835       int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
    836 
    837       if (state->single_line) {
    838          // on windows, up&down in single-line behave like left&right
    839          key = STB_TEXTEDIT_K_RIGHT | (key & STB_TEXTEDIT_K_SHIFT);
    840          goto retry;
    841       }
    842 
    843       if (sel)
    844          stb_textedit_prep_selection_at_cursor(state);
    845       else if (STB_TEXT_HAS_SELECTION(state))
    846          stb_textedit_move_to_last(str, state);
    847 
    848       // compute current position of cursor point
    849       stb_textedit_clamp(str, state);
    850       stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
    851 
    852       // now find character position down a row
    853       if (find.length) {
    854          float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
    855          float x;
    856          int start = find.first_char + find.length;
    857          state->cursor = start;
    858          STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
    859          x = row.x0;
    860          for (i = 0; i < row.num_chars; ++i) {
    861             float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
    862 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
    863             if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
    864                break;
    865 #endif
    866             x += dx;
    867             if (x > goal_x)
    868                break;
    869             ++state->cursor;
    870          }
    871          stb_textedit_clamp(str, state);
    872 
    873          state->has_preferred_x = 1;
    874          state->preferred_x = goal_x;
    875 
    876          if (sel)
    877             state->select_end = state->cursor;
    878       }
    879       break;
    880    }
    881 
    882    case STB_TEXTEDIT_K_UP:
    883    case STB_TEXTEDIT_K_UP | STB_TEXTEDIT_K_SHIFT: {
    884       StbFindState find;
    885       StbTexteditRow row;
    886       int i, sel = (key & STB_TEXTEDIT_K_SHIFT) != 0;
    887 
    888       if (state->single_line) {
    889          // on windows, up&down become left&right
    890          key = STB_TEXTEDIT_K_LEFT | (key & STB_TEXTEDIT_K_SHIFT);
    891          goto retry;
    892       }
    893 
    894       if (sel)
    895          stb_textedit_prep_selection_at_cursor(state);
    896       else if (STB_TEXT_HAS_SELECTION(state))
    897          stb_textedit_move_to_first(state);
    898 
    899       // compute current position of cursor point
    900       stb_textedit_clamp(str, state);
    901       stb_textedit_find_charpos(&find, str, state->cursor, state->single_line);
    902 
    903       // can only go up if there's a previous row
    904       if (find.prev_first != find.first_char) {
    905          // now find character position up a row
    906          float goal_x = state->has_preferred_x ? state->preferred_x : find.x;
    907          float x;
    908          state->cursor = find.prev_first;
    909          STB_TEXTEDIT_LAYOUTROW(&row, str, state->cursor);
    910          x = row.x0;
    911          for (i = 0; i < row.num_chars; ++i) {
    912             float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
    913 #ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
    914             if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
    915                break;
    916 #endif
    917             x += dx;
    918             if (x > goal_x)
    919                break;
    920             ++state->cursor;
    921          }
    922          stb_textedit_clamp(str, state);
    923 
    924          state->has_preferred_x = 1;
    925          state->preferred_x = goal_x;
    926 
    927          if (sel)
    928             state->select_end = state->cursor;
    929       }
    930       break;
    931    }
    932 
    933    case STB_TEXTEDIT_K_DELETE:
    934    case STB_TEXTEDIT_K_DELETE | STB_TEXTEDIT_K_SHIFT:
    935       if (STB_TEXT_HAS_SELECTION(state))
    936          stb_textedit_delete_selection(str, state);
    937       else {
    938          int n = STB_TEXTEDIT_STRINGLEN(str);
    939          if (state->cursor < n)
    940             stb_textedit_delete(str, state, state->cursor, 1);
    941       }
    942       state->has_preferred_x = 0;
    943       break;
    944 
    945    case STB_TEXTEDIT_K_BACKSPACE:
    946    case STB_TEXTEDIT_K_BACKSPACE | STB_TEXTEDIT_K_SHIFT:
    947       if (STB_TEXT_HAS_SELECTION(state))
    948          stb_textedit_delete_selection(str, state);
    949       else {
    950          stb_textedit_clamp(str, state);
    951          if (state->cursor > 0) {
    952             stb_textedit_delete(str, state, state->cursor - 1, 1);
    953             --state->cursor;
    954          }
    955       }
    956       state->has_preferred_x = 0;
    957       break;
    958 
    959 #ifdef STB_TEXTEDIT_K_TEXTSTART2
    960    case STB_TEXTEDIT_K_TEXTSTART2:
    961 #endif
    962    case STB_TEXTEDIT_K_TEXTSTART:
    963       state->cursor = state->select_start = state->select_end = 0;
    964       state->has_preferred_x = 0;
    965       break;
    966 
    967 #ifdef STB_TEXTEDIT_K_TEXTEND2
    968    case STB_TEXTEDIT_K_TEXTEND2:
    969 #endif
    970    case STB_TEXTEDIT_K_TEXTEND:
    971       state->cursor = STB_TEXTEDIT_STRINGLEN(str);
    972       state->select_start = state->select_end = 0;
    973       state->has_preferred_x = 0;
    974       break;
    975 
    976 #ifdef STB_TEXTEDIT_K_TEXTSTART2
    977    case STB_TEXTEDIT_K_TEXTSTART2 | STB_TEXTEDIT_K_SHIFT:
    978 #endif
    979    case STB_TEXTEDIT_K_TEXTSTART | STB_TEXTEDIT_K_SHIFT:
    980       stb_textedit_prep_selection_at_cursor(state);
    981       state->cursor = state->select_end = 0;
    982       state->has_preferred_x = 0;
    983       break;
    984 
    985 #ifdef STB_TEXTEDIT_K_TEXTEND2
    986    case STB_TEXTEDIT_K_TEXTEND2 | STB_TEXTEDIT_K_SHIFT:
    987 #endif
    988    case STB_TEXTEDIT_K_TEXTEND | STB_TEXTEDIT_K_SHIFT:
    989       stb_textedit_prep_selection_at_cursor(state);
    990       state->cursor = state->select_end = STB_TEXTEDIT_STRINGLEN(str);
    991       state->has_preferred_x = 0;
    992       break;
    993 
    994 
    995 #ifdef STB_TEXTEDIT_K_LINESTART2
    996    case STB_TEXTEDIT_K_LINESTART2:
    997 #endif
    998    case STB_TEXTEDIT_K_LINESTART:
    999       stb_textedit_clamp(str, state);
    1000       stb_textedit_move_to_first(state);
    1001       if (state->single_line)
    1002          state->cursor = 0;
    1003       else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)
    1004          --state->cursor;
    1005       state->has_preferred_x = 0;
    1006       break;
    1007 
    1008 #ifdef STB_TEXTEDIT_K_LINEEND2
    1009    case STB_TEXTEDIT_K_LINEEND2:
    1010 #endif
    1011    case STB_TEXTEDIT_K_LINEEND: {
    1012       int n = STB_TEXTEDIT_STRINGLEN(str);
    1013       stb_textedit_clamp(str, state);
    1014       stb_textedit_move_to_first(state);
    1015       if (state->single_line)
    1016          state->cursor = n;
    1017       else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
    1018          ++state->cursor;
    1019       state->has_preferred_x = 0;
    1020       break;
    1021    }
    1022 
    1023 #ifdef STB_TEXTEDIT_K_LINESTART2
    1024    case STB_TEXTEDIT_K_LINESTART2 | STB_TEXTEDIT_K_SHIFT:
    1025 #endif
    1026    case STB_TEXTEDIT_K_LINESTART | STB_TEXTEDIT_K_SHIFT:
    1027       stb_textedit_clamp(str, state);
    1028       stb_textedit_prep_selection_at_cursor(state);
    1029       if (state->single_line)
    1030          state->cursor = 0;
    1031       else while (state->cursor > 0 && STB_TEXTEDIT_GETCHAR(str, state->cursor - 1) != STB_TEXTEDIT_NEWLINE)
    1032          --state->cursor;
    1033       state->select_end = state->cursor;
    1034       state->has_preferred_x = 0;
    1035       break;
    1036 
    1037 #ifdef STB_TEXTEDIT_K_LINEEND2
    1038    case STB_TEXTEDIT_K_LINEEND2 | STB_TEXTEDIT_K_SHIFT:
    1039 #endif
    1040    case STB_TEXTEDIT_K_LINEEND | STB_TEXTEDIT_K_SHIFT: {
    1041       int n = STB_TEXTEDIT_STRINGLEN(str);
    1042       stb_textedit_clamp(str, state);
    1043       stb_textedit_prep_selection_at_cursor(state);
    1044       if (state->single_line)
    1045          state->cursor = n;
    1046       else while (state->cursor < n && STB_TEXTEDIT_GETCHAR(str, state->cursor) != STB_TEXTEDIT_NEWLINE)
    1047          ++state->cursor;
    1048       state->select_end = state->cursor;
    1049       state->has_preferred_x = 0;
    1050       break;
    1051    }
    1052 
    1053                                                        // @TODO:
    1054                                                        //    STB_TEXTEDIT_K_PGUP      - move cursor up a page
    1055                                                        //    STB_TEXTEDIT_K_PGDOWN    - move cursor down a page
    10561111   }
    10571112}
     
    10771132         int n = state->undo_rec[0].insert_length, i;
    10781133         // delete n characters from all other records
    1079          state->undo_char_point = state->undo_char_point - (short)n;  // vsnet05
    1080          STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t)((size_t)state->undo_char_point * sizeof(STB_TEXTEDIT_CHARTYPE)));
    1081          for (i = 0; i < state->undo_point; ++i)
     1134         state->undo_char_point -= n;
     1135         STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
     1136         for (i=0; i < state->undo_point; ++i)
    10821137            if (state->undo_rec[i].char_storage >= 0)
    1083                state->undo_rec[i].char_storage = state->undo_rec[i].char_storage - (short)n; // vsnet05 // @OPTIMIZE: get rid of char_storage and infer it
     1138               state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it
    10841139      }
    10851140      --state->undo_point;
    1086       STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec + 1, (size_t)((size_t)state->undo_point * sizeof(state->undo_rec[0])));
     1141      STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
    10871142   }
    10881143}
     
    10941149static void stb_textedit_discard_redo(StbUndoState *state)
    10951150{
    1096    int k = STB_TEXTEDIT_UNDOSTATECOUNT - 1;
     1151   int k = STB_TEXTEDIT_UNDOSTATECOUNT-1;
    10971152
    10981153   if (state->redo_point <= k) {
     
    11001155      if (state->undo_rec[k].char_storage >= 0) {
    11011156         int n = state->undo_rec[k].insert_length, i;
    1102          // delete n characters from all other records
    1103          state->redo_char_point = state->redo_char_point + (short)n; // vsnet05
    1104          STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point - n, (size_t)((size_t)(STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point) * sizeof(STB_TEXTEDIT_CHARTYPE)));
    1105          for (i = state->redo_point; i < k; ++i)
     1157         // move the remaining redo character data to the end of the buffer
     1158         state->redo_char_point += n;
     1159         STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
     1160         // adjust the position of all the other records to account for above memmove
     1161         for (i=state->redo_point; i < k; ++i)
    11061162            if (state->undo_rec[i].char_storage >= 0)
    1107                state->undo_rec[i].char_storage = state->undo_rec[i].char_storage + (short)n; // vsnet05
     1163               state->undo_rec[i].char_storage += n;
    11081164      }
    1109       STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point, state->undo_rec + state->redo_point - 1, (size_t)((size_t)(STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point) * sizeof(state->undo_rec[0])));
     1165      // now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
     1166      // [DEAR IMGUI]
     1167      size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
     1168      const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
     1169      const char* buf_end   = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
     1170      IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);
     1171      IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
     1172      STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
     1173
     1174      // now move redo_point to point to the new one
    11101175      ++state->redo_point;
    11111176   }
     
    11431208
    11441209   r->where = pos;
    1145    r->insert_length = (short)insert_len;
    1146    r->delete_length = (short)delete_len;
     1210   r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len;
     1211   r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len;
    11471212
    11481213   if (insert_len == 0) {
    11491214      r->char_storage = -1;
    11501215      return NULL;
    1151    }
    1152    else {
     1216   } else {
    11531217      r->char_storage = state->undo_char_point;
    1154       state->undo_char_point = state->undo_char_point + (short)insert_len;
     1218      state->undo_char_point += insert_len;
    11551219      return &state->undo_char[r->char_storage];
    11561220   }
     
    11651229
    11661230   // we need to do two things: apply the undo record, and create a redo record
    1167    u = s->undo_rec[s->undo_point - 1];
    1168    r = &s->undo_rec[s->redo_point - 1];
     1231   u = s->undo_rec[s->undo_point-1];
     1232   r = &s->undo_rec[s->redo_point-1];
    11691233   r->char_storage = -1;
    11701234
     
    11871251         // the undo records take up too much character space; there's no space to store the redo characters
    11881252         r->insert_length = 0;
    1189       }
    1190       else {
     1253      } else {
    11911254         int i;
    11921255
    11931256         // there's definitely room to store the characters eventually
    11941257         while (s->undo_char_point + u.delete_length > s->redo_char_point) {
    1195             // there's currently not enough room, so discard a redo record
    1196             stb_textedit_discard_redo(s);
    11971258            // should never happen:
    11981259            if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
    11991260               return;
     1261            // there's currently not enough room, so discard a redo record
     1262            stb_textedit_discard_redo(s);
    12001263         }
    1201          r = &s->undo_rec[s->redo_point - 1];
     1264         r = &s->undo_rec[s->redo_point-1];
    12021265
    12031266         r->char_storage = s->redo_char_point - u.delete_length;
    1204          s->redo_char_point = s->redo_char_point - (short)u.delete_length;
     1267         s->redo_char_point = s->redo_char_point - u.delete_length;
    12051268
    12061269         // now save the characters
    1207          for (i = 0; i < u.delete_length; ++i)
     1270         for (i=0; i < u.delete_length; ++i)
    12081271            s->undo_char[r->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u.where + i);
    12091272      }
     
    12521315         u->insert_length = 0;
    12531316         u->delete_length = 0;
    1254       }
    1255       else {
     1317      } else {
    12561318         int i;
    12571319         u->char_storage = s->undo_char_point;
     
    12591321
    12601322         // now save the characters
    1261          for (i = 0; i < u->insert_length; ++i)
     1323         for (i=0; i < u->insert_length; ++i)
    12621324            s->undo_char[u->char_storage + i] = STB_TEXTEDIT_GETCHAR(str, u->where + i);
    12631325      }
     
    12881350   STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
    12891351   if (p) {
    1290       for (i = 0; i < length; ++i)
    1291          p[i] = STB_TEXTEDIT_GETCHAR(str, where + i);
     1352      for (i=0; i < length; ++i)
     1353         p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
    12921354   }
    12931355}
     
    12981360   STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
    12991361   if (p) {
    1300       for (i = 0; i < old_length; ++i)
    1301          p[i] = STB_TEXTEDIT_GETCHAR(str, where + i);
     1362      for (i=0; i < old_length; ++i)
     1363         p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
    13021364   }
    13031365}
     
    13161378   state->cursor_at_end_of_line = 0;
    13171379   state->initialized = 1;
    1318    state->single_line = (unsigned char)is_single_line;
     1380   state->single_line = (unsigned char) is_single_line;
    13191381   state->insert_mode = 0;
     1382   state->row_count_per_page = 0;
    13201383}
    13211384
     
    13251388   stb_textedit_clear_state(state, is_single_line);
    13261389}
     1390
     1391#if defined(__GNUC__) || defined(__clang__)
     1392#pragma GCC diagnostic push
     1393#pragma GCC diagnostic ignored "-Wcast-qual"
     1394#endif
     1395
     1396static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
     1397{
     1398   return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len);
     1399}
     1400
     1401#if defined(__GNUC__) || defined(__clang__)
     1402#pragma GCC diagnostic pop
     1403#endif
     1404
    13271405#endif//STB_TEXTEDIT_IMPLEMENTATION
     1406
     1407/*
     1408------------------------------------------------------------------------------
     1409This software is available under 2 licenses -- choose whichever you prefer.
     1410------------------------------------------------------------------------------
     1411ALTERNATIVE A - MIT License
     1412Copyright (c) 2017 Sean Barrett
     1413Permission is hereby granted, free of charge, to any person obtaining a copy of
     1414this software and associated documentation files (the "Software"), to deal in
     1415the Software without restriction, including without limitation the rights to
     1416use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
     1417of the Software, and to permit persons to whom the Software is furnished to do
     1418so, subject to the following conditions:
     1419The above copyright notice and this permission notice shall be included in all
     1420copies or substantial portions of the Software.
     1421THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     1422IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     1423FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     1424AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     1425LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     1426OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     1427SOFTWARE.
     1428------------------------------------------------------------------------------
     1429ALTERNATIVE B - Public Domain (www.unlicense.org)
     1430This is free and unencumbered software released into the public domain.
     1431Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
     1432software, either in source code form or as a compiled binary, for any purpose,
     1433commercial or non-commercial, and by any means.
     1434In jurisdictions that recognize copyright laws, the author or authors of this
     1435software dedicate any and all copyright interest in the software to the public
     1436domain. We make this dedication for the benefit of the public at large and to
     1437the detriment of our heirs and successors. We intend this dedication to be an
     1438overt act of relinquishment in perpetuity of all present and future rights to
     1439this software under copyright law.
     1440THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     1441IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     1442FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     1443AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     1444ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     1445WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     1446------------------------------------------------------------------------------
     1447*/
  • IMGUI/imstb_truetype.h

    r78c3045 re66fd66  
    1 // stb_truetype.h - v1.19 - public domain
     1// [DEAR IMGUI]
     2// This is a slightly modified version of stb_truetype.h 1.20.
     3// Mostly fixing for compiler and static analyzer warnings.
     4// Grep for [DEAR IMGUI] to find the changes.
     5
     6// stb_truetype.h - v1.20 - public domain
    27// authored from 2009-2016 by Sean Barrett / RAD Game Tools
    38//
     
    5055// VERSION HISTORY
    5156//
     57//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
    5258//   1.19 (2018-02-11) GPOS kerning, STBTT_fmod
    5359//   1.18 (2018-01-29) add missing function
     
    7682// USAGE
    7783//
    78 //   Include this file in whatever places neeed to refer to it. In ONE C/C++
     84//   Include this file in whatever places need to refer to it. In ONE C/C++
    7985//   file, write:
    8086//      #define STB_TRUETYPE_IMPLEMENTATION
     
    248254//   Sample code                        140 LOC  /
    249255//   Truetype parsing                   620 LOC  ---- 620 LOC TrueType
    250 //   Software rasterization             240 LOC  \                           .
    251 //   Curve tesselation                  120 LOC   \__ 550 LOC Bitmap creation
     256//   Software rasterization             240 LOC  \.
     257//   Curve tessellation                 120 LOC   \__ 550 LOC Bitmap creation
    252258//   Bitmap management                  100 LOC   /
    253259//   Baked bitmap interface              70 LOC  /
     
    276282#include "stb_truetype.h"
    277283
    278 unsigned char ttf_buffer[1 << 20];
    279 unsigned char temp_bitmap[512 * 512];
     284unsigned char ttf_buffer[1<<20];
     285unsigned char temp_bitmap[512*512];
    280286
    281287stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs
     
    284290void my_stbtt_initfont(void)
    285291{
    286    fread(ttf_buffer, 1, 1 << 20, fopen("c:/windows/fonts/times.ttf", "rb"));
    287    stbtt_BakeFontBitmap(ttf_buffer, 0, 32.0, temp_bitmap, 512, 512, 32, 96, cdata); // no guarantee this fits!
    288                                                                                     // can free ttf_buffer at this point
     292   fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));
     293   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!
     294   // can free ttf_buffer at this point
    289295   glGenTextures(1, &ftex);
    290296   glBindTexture(GL_TEXTURE_2D, ftex);
    291    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512, 512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
     297   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);
    292298   // can free temp_bitmap at this point
    293299   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     
    303309      if (*text >= 32 && *text < 128) {
    304310         stbtt_aligned_quad q;
    305          stbtt_GetBakedQuad(cdata, 512, 512, *text - 32, &x, &y, &q, 1);//1=opengl & d3d10+,0=d3d9
    306          glTexCoord2f(q.s0, q.t1); glVertex2f(q.x0, q.y0);
    307          glTexCoord2f(q.s1, q.t1); glVertex2f(q.x1, q.y0);
    308          glTexCoord2f(q.s1, q.t0); glVertex2f(q.x1, q.y1);
    309          glTexCoord2f(q.s0, q.t0); glVertex2f(q.x0, q.y1);
     311         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
     312         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
     313         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
     314         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
     315         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
    310316      }
    311317      ++text;
     
    325331#include "stb_truetype.h"
    326332
    327 char ttf_buffer[1 << 25];
     333char ttf_buffer[1<<25];
    328334
    329335int main(int argc, char **argv)
     
    331337   stbtt_fontinfo font;
    332338   unsigned char *bitmap;
    333    int w, h, i, j, c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
    334 
    335    fread(ttf_buffer, 1, 1 << 25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
    336 
    337    stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0));
    338    bitmap = stbtt_GetCodepointBitmap(&font, 0, stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0, 0);
    339 
    340    for (j = 0; j < h; ++j) {
    341       for (i = 0; i < w; ++i)
    342          putchar(" .:ioVM@"[bitmap[j*w + i] >> 5]);
     339   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);
     340
     341   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));
     342
     343   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));
     344   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);
     345
     346   for (j=0; j < h; ++j) {
     347      for (i=0; i < w; ++i)
     348         putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);
    343349      putchar('\n');
    344350   }
     
    365371//
    366372#if 0
    367 char buffer[24 << 20];
     373char buffer[24<<20];
    368374unsigned char screen[20][79];
    369375
     
    371377{
    372378   stbtt_fontinfo font;
    373    int i, j, ascent, baseline, ch = 0;
    374    float scale, xpos = 2; // leave a little padding in case the character extends left
     379   int i,j,ascent,baseline,ch=0;
     380   float scale, xpos=2; // leave a little padding in case the character extends left
    375381   char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness
    376382
     
    379385
    380386   scale = stbtt_ScaleForPixelHeight(&font, 15);
    381    stbtt_GetFontVMetrics(&font, &ascent, 0, 0);
    382    baseline = (int)(ascent*scale);
     387   stbtt_GetFontVMetrics(&font, &ascent,0,0);
     388   baseline = (int) (ascent*scale);
    383389
    384390   while (text[ch]) {
    385       int advance, lsb, x0, y0, x1, y1;
    386       float x_shift = xpos - (float)floor(xpos);
     391      int advance,lsb,x0,y0,x1,y1;
     392      float x_shift = xpos - (float) floor(xpos);
    387393      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);
    388       stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale, scale, x_shift, 0, &x0, &y0, &x1, &y1);
    389       stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int)xpos + x0], x1 - x0, y1 - y0, 79, scale, scale, x_shift, 0, text[ch]);
     394      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);
     395      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);
    390396      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong
    391397      // because this API is really for baking character bitmaps into textures. if you want to render
     
    393399      // "alpha blend" that into the working buffer
    394400      xpos += (advance * scale);
    395       if (text[ch + 1])
    396          xpos += scale * stbtt_GetCodepointKernAdvance(&font, text[ch], text[ch + 1]);
     401      if (text[ch+1])
     402         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);
    397403      ++ch;
    398404   }
    399405
    400    for (j = 0; j < 20; ++j) {
    401       for (i = 0; i < 78; ++i)
    402          putchar(" .:ioVM@"[screen[j][i] >> 5]);
     406   for (j=0; j < 20; ++j) {
     407      for (i=0; i < 78; ++i)
     408         putchar(" .:ioVM@"[screen[j][i]>>5]);
    403409      putchar('\n');
    404410   }
     
    419425
    420426#ifdef STB_TRUETYPE_IMPLEMENTATION
    421 // #define your own (u)stbtt_int8/16/32 before including to override this
    422 #ifndef stbtt_uint8
    423 typedef unsigned char   stbtt_uint8;
    424 typedef signed   char   stbtt_int8;
    425 typedef unsigned short  stbtt_uint16;
    426 typedef signed   short  stbtt_int16;
    427 typedef unsigned int    stbtt_uint32;
    428 typedef signed   int    stbtt_int32;
    429 #endif
    430 
    431 typedef char stbtt__check_size32[sizeof(stbtt_int32) == 4 ? 1 : -1];
    432 typedef char stbtt__check_size16[sizeof(stbtt_int16) == 2 ? 1 : -1];
    433 
    434 // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
    435 #ifndef STBTT_ifloor
    436 #include <math.h>
    437 #define STBTT_ifloor(x)   ((int) floor(x))
    438 #define STBTT_iceil(x)    ((int) ceil(x))
    439 #endif
    440 
    441 #ifndef STBTT_sqrt
    442 #include <math.h>
    443 #define STBTT_sqrt(x)      sqrt(x)
    444 #define STBTT_pow(x,y)     pow(x,y)
    445 #endif
    446 
    447 #ifndef STBTT_fmod
    448 #include <math.h>
    449 #define STBTT_fmod(x,y)    fmod(x,y)
    450 #endif
    451 
    452 #ifndef STBTT_cos
    453 #include <math.h>
    454 #define STBTT_cos(x)       cos(x)
    455 #define STBTT_acos(x)      acos(x)
    456 #endif
    457 
    458 #ifndef STBTT_fabs
    459 #include <math.h>
    460 #define STBTT_fabs(x)      fabs(x)
    461 #endif
    462 
    463 // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
    464 #ifndef STBTT_malloc
    465 #include <stdlib.h>
    466 #define STBTT_malloc(x,u)  ((void)(u),malloc(x))
    467 #define STBTT_free(x,u)    ((void)(u),free(x))
    468 #endif
    469 
    470 #ifndef STBTT_assert
    471 #include <assert.h>
    472 #define STBTT_assert(x)    assert(x)
    473 #endif
    474 
    475 #ifndef STBTT_strlen
    476 #include <string.h>
    477 #define STBTT_strlen(x)    strlen(x)
    478 #endif
    479 
    480 #ifndef STBTT_memcpy
    481 #include <string.h>
    482 #define STBTT_memcpy       memcpy
    483 #define STBTT_memset       memset
    484 #endif
     427   // #define your own (u)stbtt_int8/16/32 before including to override this
     428   #ifndef stbtt_uint8
     429   typedef unsigned char   stbtt_uint8;
     430   typedef signed   char   stbtt_int8;
     431   typedef unsigned short  stbtt_uint16;
     432   typedef signed   short  stbtt_int16;
     433   typedef unsigned int    stbtt_uint32;
     434   typedef signed   int    stbtt_int32;
     435   #endif
     436
     437   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];
     438   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];
     439
     440   // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h
     441   #ifndef STBTT_ifloor
     442   #include <math.h>
     443   #define STBTT_ifloor(x)   ((int) floor(x))
     444   #define STBTT_iceil(x)    ((int) ceil(x))
     445   #endif
     446
     447   #ifndef STBTT_sqrt
     448   #include <math.h>
     449   #define STBTT_sqrt(x)      sqrt(x)
     450   #define STBTT_pow(x,y)     pow(x,y)
     451   #endif
     452
     453   #ifndef STBTT_fmod
     454   #include <math.h>
     455   #define STBTT_fmod(x,y)    fmod(x,y)
     456   #endif
     457
     458   #ifndef STBTT_cos
     459   #include <math.h>
     460   #define STBTT_cos(x)       cos(x)
     461   #define STBTT_acos(x)      acos(x)
     462   #endif
     463
     464   #ifndef STBTT_fabs
     465   #include <math.h>
     466   #define STBTT_fabs(x)      fabs(x)
     467   #endif
     468
     469   // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h
     470   #ifndef STBTT_malloc
     471   #include <stdlib.h>
     472   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))
     473   #define STBTT_free(x,u)    ((void)(u),free(x))
     474   #endif
     475
     476   #ifndef STBTT_assert
     477   #include <assert.h>
     478   #define STBTT_assert(x)    assert(x)
     479   #endif
     480
     481   #ifndef STBTT_strlen
     482   #include <string.h>
     483   #define STBTT_strlen(x)    strlen(x)
     484   #endif
     485
     486   #ifndef STBTT_memcpy
     487   #include <string.h>
     488   #define STBTT_memcpy       memcpy
     489   #define STBTT_memset       memset
     490   #endif
    485491#endif
    486492
     
    505511#endif
    506512
    507    // private structure
    508    typedef struct
    509    {
    510       unsigned char *data;
    511       int cursor;
    512       int size;
    513    } stbtt__buf;
    514 
    515    //////////////////////////////////////////////////////////////////////////////
    516    //
    517    // TEXTURE BAKING API
    518    //
    519    // If you use this API, you only have to call two functions ever.
    520    //
    521 
    522    typedef struct
    523    {
    524       unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap
    525       float xoff, yoff, xadvance;
    526    } stbtt_bakedchar;
    527 
    528    STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
    529       float pixel_height,                     // height of font in pixels
    530       unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
    531       int first_char, int num_chars,          // characters to bake
    532       stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long
    533                                               // if return is positive, the first unused row of the bitmap
    534                                               // if return is negative, returns the negative of the number of characters that fit
    535                                               // if return is 0, no characters fit and no rows were used
    536                                               // This uses a very crappy packing.
    537 
    538    typedef struct
    539    {
    540       float x0, y0, s0, t0; // top-left
    541       float x1, y1, s1, t1; // bottom-right
    542    } stbtt_aligned_quad;
    543 
    544    STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  // same data as above
    545       int char_index,             // character to display
    546       float *xpos, float *ypos,   // pointers to current position in screen pixel space
    547       stbtt_aligned_quad *q,      // output: quad to draw
    548       int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier
    549                                   // Call GetBakedQuad with char_index = 'character - first_char', and it
    550                                   // creates the quad you need to draw and advances the current position.
    551                                   //
    552                                   // The coordinate system used assumes y increases downwards.
    553                                   //
    554                                   // Characters will extend both above and below the current position;
    555                                   // see discussion of "BASELINE" above.
    556                                   //
    557                                   // It's inefficient; you might want to c&p it and optimize it.
    558 
    559 
    560 
    561                                   //////////////////////////////////////////////////////////////////////////////
    562                                   //
    563                                   // NEW TEXTURE BAKING API
    564                                   //
    565                                   // This provides options for packing multiple fonts into one atlas, not
    566                                   // perfectly but better than nothing.
    567 
    568    typedef struct
    569    {
    570       unsigned short x0, y0, x1, y1; // coordinates of bbox in bitmap
    571       float xoff, yoff, xadvance;
    572       float xoff2, yoff2;
    573    } stbtt_packedchar;
    574 
    575    typedef struct stbtt_pack_context stbtt_pack_context;
    576    typedef struct stbtt_fontinfo stbtt_fontinfo;
     513// private structure
     514typedef struct
     515{
     516   unsigned char *data;
     517   int cursor;
     518   int size;
     519} stbtt__buf;
     520
     521//////////////////////////////////////////////////////////////////////////////
     522//
     523// TEXTURE BAKING API
     524//
     525// If you use this API, you only have to call two functions ever.
     526//
     527
     528typedef struct
     529{
     530   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
     531   float xoff,yoff,xadvance;
     532} stbtt_bakedchar;
     533
     534STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
     535                                float pixel_height,                     // height of font in pixels
     536                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
     537                                int first_char, int num_chars,          // characters to bake
     538                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long
     539// if return is positive, the first unused row of the bitmap
     540// if return is negative, returns the negative of the number of characters that fit
     541// if return is 0, no characters fit and no rows were used
     542// This uses a very crappy packing.
     543
     544typedef struct
     545{
     546   float x0,y0,s0,t0; // top-left
     547   float x1,y1,s1,t1; // bottom-right
     548} stbtt_aligned_quad;
     549
     550STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  // same data as above
     551                               int char_index,             // character to display
     552                               float *xpos, float *ypos,   // pointers to current position in screen pixel space
     553                               stbtt_aligned_quad *q,      // output: quad to draw
     554                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier
     555// Call GetBakedQuad with char_index = 'character - first_char', and it
     556// creates the quad you need to draw and advances the current position.
     557//
     558// The coordinate system used assumes y increases downwards.
     559//
     560// Characters will extend both above and below the current position;
     561// see discussion of "BASELINE" above.
     562//
     563// It's inefficient; you might want to c&p it and optimize it.
     564
     565STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);
     566// Query the font vertical metrics without having to create a font first.
     567
     568
     569//////////////////////////////////////////////////////////////////////////////
     570//
     571// NEW TEXTURE BAKING API
     572//
     573// This provides options for packing multiple fonts into one atlas, not
     574// perfectly but better than nothing.
     575
     576typedef struct
     577{
     578   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap
     579   float xoff,yoff,xadvance;
     580   float xoff2,yoff2;
     581} stbtt_packedchar;
     582
     583typedef struct stbtt_pack_context stbtt_pack_context;
     584typedef struct stbtt_fontinfo stbtt_fontinfo;
    577585#ifndef STB_RECT_PACK_VERSION
    578    typedef struct stbrp_rect stbrp_rect;
     586typedef struct stbrp_rect stbrp_rect;
    579587#endif
    580588
    581    STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
    582    // Initializes a packing context stored in the passed-in stbtt_pack_context.
    583    // Future calls using this context will pack characters into the bitmap passed
    584    // in here: a 1-channel bitmap that is width * height. stride_in_bytes is
    585    // the distance from one row to the next (or 0 to mean they are packed tightly
    586    // together). "padding" is the amount of padding to leave between each
    587    // character (normally you want '1' for bitmaps you'll use as textures with
    588    // bilinear filtering).
    589    //
    590    // Returns 0 on failure, 1 on success.
    591 
    592    STBTT_DEF void stbtt_PackEnd(stbtt_pack_context *spc);
    593    // Cleans up the packing context and frees all memory.
     589STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
     590// Initializes a packing context stored in the passed-in stbtt_pack_context.
     591// Future calls using this context will pack characters into the bitmap passed
     592// in here: a 1-channel bitmap that is width * height. stride_in_bytes is
     593// the distance from one row to the next (or 0 to mean they are packed tightly
     594// together). "padding" is the amount of padding to leave between each
     595// character (normally you want '1' for bitmaps you'll use as textures with
     596// bilinear filtering).
     597//
     598// Returns 0 on failure, 1 on success.
     599
     600STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);
     601// Cleans up the packing context and frees all memory.
    594602
    595603#define STBTT_POINT_SIZE(x)   (-(x))
    596604
    597    STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
    598       int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
    599    // Creates character bitmaps from the font_index'th font found in fontdata (use
    600    // font_index=0 if you don't know what that is). It creates num_chars_in_range
    601    // bitmaps for characters with unicode values starting at first_unicode_char_in_range
    602    // and increasing. Data for how to render them is stored in chardata_for_range;
    603    // pass these to stbtt_GetPackedQuad to get back renderable quads.
    604    //
    605    // font_size is the full height of the character from ascender to descender,
    606    // as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
    607    // by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
    608    // and pass that result as 'font_size':
    609    //       ...,                  20 , ... // font max minus min y is 20 pixels tall
    610    //       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
    611 
    612    typedef struct
    613    {
    614       float font_size;
    615       int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint
    616       int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints
    617       int num_chars;
    618       stbtt_packedchar *chardata_for_range; // output
    619       unsigned char h_oversample, v_oversample; // don't set these, they're used internally
    620    } stbtt_pack_range;
    621 
    622    STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
    623    // Creates character bitmaps from multiple ranges of characters stored in
    624    // ranges. This will usually create a better-packed bitmap than multiple
    625    // calls to stbtt_PackFontRange. Note that you can call this multiple
    626    // times within a single PackBegin/PackEnd.
    627 
    628    STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
    629    // Oversampling a font increases the quality by allowing higher-quality subpixel
    630    // positioning, and is especially valuable at smaller text sizes.
    631    //
    632    // This function sets the amount of oversampling for all following calls to
    633    // stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
    634    // pack context. The default (no oversampling) is achieved by h_oversample=1
    635    // and v_oversample=1. The total number of pixels required is
    636    // h_oversample*v_oversample larger than the default; for example, 2x2
    637    // oversampling requires 4x the storage of 1x1. For best results, render
    638    // oversampled textures with bilinear filtering. Look at the readme in
    639    // stb/tests/oversample for information about oversampled fonts
    640    //
    641    // To use with PackFontRangesGather etc., you must set it before calls
    642    // call to PackFontRangesGatherRects.
    643 
    644    STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  // same data as above
    645       int char_index,             // character to display
    646       float *xpos, float *ypos,   // pointers to current position in screen pixel space
    647       stbtt_aligned_quad *q,      // output: quad to draw
    648       int align_to_integer);
    649 
    650    STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
    651    STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
    652    STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
    653    // Calling these functions in sequence is roughly equivalent to calling
    654    // stbtt_PackFontRanges(). If you more control over the packing of multiple
    655    // fonts, or if you want to pack custom data into a font texture, take a look
    656    // at the source to of stbtt_PackFontRanges() and create a custom version
    657    // using these functions, e.g. call GatherRects multiple times,
    658    // building up a single array of rects, then call PackRects once,
    659    // then call RenderIntoRects repeatedly. This may result in a
    660    // better packing than calling PackFontRanges multiple times
    661    // (or it may not).
    662 
    663    // this is an opaque structure that you shouldn't mess with which holds
    664    // all the context needed from PackBegin to PackEnd.
    665    struct stbtt_pack_context {
    666       void *user_allocator_context;
    667       void *pack_info;
    668       int   width;
    669       int   height;
    670       int   stride_in_bytes;
    671       int   padding;
    672       unsigned int   h_oversample, v_oversample;
    673       unsigned char *pixels;
    674       void  *nodes;
    675    };
    676 
    677    //////////////////////////////////////////////////////////////////////////////
    678    //
    679    // FONT LOADING
    680    //
    681    //
    682 
    683    STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
    684    // This function will determine the number of fonts in a font file.  TrueType
    685    // collection (.ttc) files may contain multiple fonts, while TrueType font
    686    // (.ttf) files only contain one font. The number of fonts can be used for
    687    // indexing with the previous function where the index is between zero and one
    688    // less than the total fonts. If an error occurs, -1 is returned.
    689 
    690    STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
    691    // Each .ttf/.ttc file may have more than one font. Each font has a sequential
    692    // index number starting from 0. Call this function to get the font offset for
    693    // a given index; it returns -1 if the index is out of range. A regular .ttf
    694    // file will only define one font and it always be at offset 0, so it will
    695    // return '0' for index 0, and -1 for all other indices.
    696 
    697    // The following structure is defined publically so you can declare one on
    698    // the stack or as a global or etc, but you should treat it as opaque.
    699    struct stbtt_fontinfo
    700    {
    701       void           * userdata;
    702       unsigned char  * data;              // pointer to .ttf file
    703       int              fontstart;         // offset of start of font
    704 
    705       int numGlyphs;                     // number of glyphs, needed for range checking
    706 
    707       int loca, head, glyf, hhea, hmtx, kern, gpos; // table locations as offset from start of .ttf
    708       int index_map;                     // a cmap mapping for our chosen character encoding
    709       int indexToLocFormat;              // format needed to map from glyph index to glyph
    710 
    711       stbtt__buf cff;                    // cff font data
    712       stbtt__buf charstrings;            // the charstring index
    713       stbtt__buf gsubrs;                 // global charstring subroutines index
    714       stbtt__buf subrs;                  // private charstring subroutines index
    715       stbtt__buf fontdicts;              // array of font dicts
    716       stbtt__buf fdselect;               // map from glyph to fontdict
    717    };
    718 
    719    STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
    720    // Given an offset into the file that defines a font, this function builds
    721    // the necessary cached info for the rest of the system. You must allocate
    722    // the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
    723    // need to do anything special to free it, because the contents are pure
    724    // value data with no additional data structures. Returns 0 on failure.
    725 
    726 
    727    //////////////////////////////////////////////////////////////////////////////
    728    //
    729    // CHARACTER TO GLYPH-INDEX CONVERSIOn
    730 
    731    STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
    732    // If you're going to perform multiple operations on the same character
    733    // and you want a speed-up, call this function with the character you're
    734    // going to process, then use glyph-based functions instead of the
    735    // codepoint-based functions.
    736 
    737 
    738    //////////////////////////////////////////////////////////////////////////////
    739    //
    740    // CHARACTER PROPERTIES
    741    //
    742 
    743    STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
    744    // computes a scale factor to produce a font whose "height" is 'pixels' tall.
    745    // Height is measured as the distance from the highest ascender to the lowest
    746    // descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
    747    // and computing:
    748    //       scale = pixels / (ascent - descent)
    749    // so if you prefer to measure height by the ascent only, use a similar calculation.
    750 
    751    STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
    752    // computes a scale factor to produce a font whose EM size is mapped to
    753    // 'pixels' tall. This is probably what traditional APIs compute, but
    754    // I'm not positive.
    755 
    756    STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
    757    // ascent is the coordinate above the baseline the font extends; descent
    758    // is the coordinate below the baseline the font extends (i.e. it is typically negative)
    759    // lineGap is the spacing between one row's descent and the next row's ascent...
    760    // so you should advance the vertical position by "*ascent - *descent + *lineGap"
    761    //   these are expressed in unscaled coordinates, so you must multiply by
    762    //   the scale factor for a given size
    763 
    764    STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
    765    // analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
    766    // table (specific to MS/Windows TTF files).
    767    //
    768    // Returns 1 on success (table present), 0 on failure.
    769 
    770    STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
    771    // the bounding box around all possible characters
    772 
    773    STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
    774    // leftSideBearing is the offset from the current horizontal position to the left edge of the character
    775    // advanceWidth is the offset from the current horizontal position to the next horizontal position
    776    //   these are expressed in unscaled coordinates
    777 
    778    STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
    779    // an additional amount to add to the 'advance' value between ch1 and ch2
    780 
    781    STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
    782    // Gets the bounding box of the visible part of the glyph, in unscaled coordinates
    783 
    784    STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
    785    STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
    786    STBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
    787    // as above, but takes one or more glyph indices for greater efficiency
    788 
    789 
    790    //////////////////////////////////////////////////////////////////////////////
    791    //
    792    // GLYPH SHAPES (you probably don't need these, but they have to go before
    793    // the bitmaps for C declaration-order reasons)
    794    //
     605STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
     606                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
     607// Creates character bitmaps from the font_index'th font found in fontdata (use
     608// font_index=0 if you don't know what that is). It creates num_chars_in_range
     609// bitmaps for characters with unicode values starting at first_unicode_char_in_range
     610// and increasing. Data for how to render them is stored in chardata_for_range;
     611// pass these to stbtt_GetPackedQuad to get back renderable quads.
     612//
     613// font_size is the full height of the character from ascender to descender,
     614// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed
     615// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()
     616// and pass that result as 'font_size':
     617//       ...,                  20 , ... // font max minus min y is 20 pixels tall
     618//       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall
     619
     620typedef struct
     621{
     622   float font_size;
     623   int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint
     624   int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints
     625   int num_chars;
     626   stbtt_packedchar *chardata_for_range; // output
     627   unsigned char h_oversample, v_oversample; // don't set these, they're used internally
     628} stbtt_pack_range;
     629
     630STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
     631// Creates character bitmaps from multiple ranges of characters stored in
     632// ranges. This will usually create a better-packed bitmap than multiple
     633// calls to stbtt_PackFontRange. Note that you can call this multiple
     634// times within a single PackBegin/PackEnd.
     635
     636STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);
     637// Oversampling a font increases the quality by allowing higher-quality subpixel
     638// positioning, and is especially valuable at smaller text sizes.
     639//
     640// This function sets the amount of oversampling for all following calls to
     641// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given
     642// pack context. The default (no oversampling) is achieved by h_oversample=1
     643// and v_oversample=1. The total number of pixels required is
     644// h_oversample*v_oversample larger than the default; for example, 2x2
     645// oversampling requires 4x the storage of 1x1. For best results, render
     646// oversampled textures with bilinear filtering. Look at the readme in
     647// stb/tests/oversample for information about oversampled fonts
     648//
     649// To use with PackFontRangesGather etc., you must set it before calls
     650// call to PackFontRangesGatherRects.
     651
     652STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
     653// If skip != 0, this tells stb_truetype to skip any codepoints for which
     654// there is no corresponding glyph. If skip=0, which is the default, then
     655// codepoints without a glyph recived the font's "missing character" glyph,
     656// typically an empty box by convention.
     657
     658STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  // same data as above
     659                               int char_index,             // character to display
     660                               float *xpos, float *ypos,   // pointers to current position in screen pixel space
     661                               stbtt_aligned_quad *q,      // output: quad to draw
     662                               int align_to_integer);
     663
     664STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
     665STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
     666STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
     667// Calling these functions in sequence is roughly equivalent to calling
     668// stbtt_PackFontRanges(). If you more control over the packing of multiple
     669// fonts, or if you want to pack custom data into a font texture, take a look
     670// at the source to of stbtt_PackFontRanges() and create a custom version
     671// using these functions, e.g. call GatherRects multiple times,
     672// building up a single array of rects, then call PackRects once,
     673// then call RenderIntoRects repeatedly. This may result in a
     674// better packing than calling PackFontRanges multiple times
     675// (or it may not).
     676
     677// this is an opaque structure that you shouldn't mess with which holds
     678// all the context needed from PackBegin to PackEnd.
     679struct stbtt_pack_context {
     680   void *user_allocator_context;
     681   void *pack_info;
     682   int   width;
     683   int   height;
     684   int   stride_in_bytes;
     685   int   padding;
     686   int   skip_missing;
     687   unsigned int   h_oversample, v_oversample;
     688   unsigned char *pixels;
     689   void  *nodes;
     690};
     691
     692//////////////////////////////////////////////////////////////////////////////
     693//
     694// FONT LOADING
     695//
     696//
     697
     698STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
     699// This function will determine the number of fonts in a font file.  TrueType
     700// collection (.ttc) files may contain multiple fonts, while TrueType font
     701// (.ttf) files only contain one font. The number of fonts can be used for
     702// indexing with the previous function where the index is between zero and one
     703// less than the total fonts. If an error occurs, -1 is returned.
     704
     705STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
     706// Each .ttf/.ttc file may have more than one font. Each font has a sequential
     707// index number starting from 0. Call this function to get the font offset for
     708// a given index; it returns -1 if the index is out of range. A regular .ttf
     709// file will only define one font and it always be at offset 0, so it will
     710// return '0' for index 0, and -1 for all other indices.
     711
     712// The following structure is defined publicly so you can declare one on
     713// the stack or as a global or etc, but you should treat it as opaque.
     714struct stbtt_fontinfo
     715{
     716   void           * userdata;
     717   unsigned char  * data;              // pointer to .ttf file
     718   int              fontstart;         // offset of start of font
     719
     720   int numGlyphs;                     // number of glyphs, needed for range checking
     721
     722   int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf
     723   int index_map;                     // a cmap mapping for our chosen character encoding
     724   int indexToLocFormat;              // format needed to map from glyph index to glyph
     725
     726   stbtt__buf cff;                    // cff font data
     727   stbtt__buf charstrings;            // the charstring index
     728   stbtt__buf gsubrs;                 // global charstring subroutines index
     729   stbtt__buf subrs;                  // private charstring subroutines index
     730   stbtt__buf fontdicts;              // array of font dicts
     731   stbtt__buf fdselect;               // map from glyph to fontdict
     732};
     733
     734STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
     735// Given an offset into the file that defines a font, this function builds
     736// the necessary cached info for the rest of the system. You must allocate
     737// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't
     738// need to do anything special to free it, because the contents are pure
     739// value data with no additional data structures. Returns 0 on failure.
     740
     741
     742//////////////////////////////////////////////////////////////////////////////
     743//
     744// CHARACTER TO GLYPH-INDEX CONVERSIOn
     745
     746STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);
     747// If you're going to perform multiple operations on the same character
     748// and you want a speed-up, call this function with the character you're
     749// going to process, then use glyph-based functions instead of the
     750// codepoint-based functions.
     751// Returns 0 if the character codepoint is not defined in the font.
     752
     753
     754//////////////////////////////////////////////////////////////////////////////
     755//
     756// CHARACTER PROPERTIES
     757//
     758
     759STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);
     760// computes a scale factor to produce a font whose "height" is 'pixels' tall.
     761// Height is measured as the distance from the highest ascender to the lowest
     762// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics
     763// and computing:
     764//       scale = pixels / (ascent - descent)
     765// so if you prefer to measure height by the ascent only, use a similar calculation.
     766
     767STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);
     768// computes a scale factor to produce a font whose EM size is mapped to
     769// 'pixels' tall. This is probably what traditional APIs compute, but
     770// I'm not positive.
     771
     772STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);
     773// ascent is the coordinate above the baseline the font extends; descent
     774// is the coordinate below the baseline the font extends (i.e. it is typically negative)
     775// lineGap is the spacing between one row's descent and the next row's ascent...
     776// so you should advance the vertical position by "*ascent - *descent + *lineGap"
     777//   these are expressed in unscaled coordinates, so you must multiply by
     778//   the scale factor for a given size
     779
     780STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
     781// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
     782// table (specific to MS/Windows TTF files).
     783//
     784// Returns 1 on success (table present), 0 on failure.
     785
     786STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
     787// the bounding box around all possible characters
     788
     789STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);
     790// leftSideBearing is the offset from the current horizontal position to the left edge of the character
     791// advanceWidth is the offset from the current horizontal position to the next horizontal position
     792//   these are expressed in unscaled coordinates
     793
     794STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);
     795// an additional amount to add to the 'advance' value between ch1 and ch2
     796
     797STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);
     798// Gets the bounding box of the visible part of the glyph, in unscaled coordinates
     799
     800STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);
     801STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);
     802STBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
     803// as above, but takes one or more glyph indices for greater efficiency
     804
     805
     806//////////////////////////////////////////////////////////////////////////////
     807//
     808// GLYPH SHAPES (you probably don't need these, but they have to go before
     809// the bitmaps for C declaration-order reasons)
     810//
    795811
    796812#ifndef STBTT_vmove // you can predefine these to use different values (but why?)
    797813   enum {
    798       STBTT_vmove = 1,
     814      STBTT_vmove=1,
    799815      STBTT_vline,
    800816      STBTT_vcurve,
     
    804820
    805821#ifndef stbtt_vertex // you can predefine this to use different values
    806    // (we share this with other code at RAD)
    807 #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
     822                   // (we share this with other code at RAD)
     823   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
    808824   typedef struct
    809825   {
    810       stbtt_vertex_type x, y, cx, cy, cx1, cy1;
    811       unsigned char type, padding;
     826      stbtt_vertex_type x,y,cx,cy,cx1,cy1;
     827      unsigned char type,padding;
    812828   } stbtt_vertex;
    813829#endif
    814830
    815    STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
    816    // returns non-zero if nothing is drawn for this glyph
    817 
    818    STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
    819    STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
    820    // returns # of vertices and fills *vertices with the pointer to them
    821    //   these are expressed in "unscaled" coordinates
    822    //
    823    // The shape is a series of countours. Each one starts with
    824    // a STBTT_moveto, then consists of a series of mixed
    825    // STBTT_lineto and STBTT_curveto segments. A lineto
    826    // draws a line from previous endpoint to its x,y; a curveto
    827    // draws a quadratic bezier from previous endpoint to
    828    // its x,y, using cx,cy as the bezier control point.
    829 
    830    STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
    831    // frees the data allocated above
    832 
    833    //////////////////////////////////////////////////////////////////////////////
    834    //
    835    // BITMAP RENDERING
    836    //
    837 
    838    STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
    839    // frees the bitmap allocated below
    840 
    841    STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
    842    // allocates a large-enough single-channel 8bpp bitmap and renders the
    843    // specified character/glyph at the specified scale into it, with
    844    // antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
    845    // *width & *height are filled out with the width & height of the bitmap,
    846    // which is stored left-to-right, top-to-bottom.
    847    //
    848    // xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
    849 
    850    STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
    851    // the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
    852    // shift for the character
    853 
    854    STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
    855    // the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
    856    // in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
    857    // is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
    858    // width and height and positioning info for it first.
    859 
    860    STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);
    861    // same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
    862    // shift for the character
    863 
    864    STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
    865    // same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
    866    // is performed (see stbtt_PackSetOversampling)
    867 
    868    STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
    869    // get the bbox of the bitmap centered around the glyph origin; so the
    870    // bitmap width is ix1-ix0, height is iy1-iy0, and location to place
    871    // the bitmap top left is (leftSideBearing*scale,iy0).
    872    // (Note that the bitmap uses y-increases-down, but the shape uses
    873    // y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
    874 
    875    STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
    876    // same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
    877    // shift for the character
    878 
    879    // the following functions are equivalent to the above functions, but operate
    880    // on glyph indices instead of Unicode codepoints (for efficiency)
    881    STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
    882    STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
    883    STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
    884    STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
    885    STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
    886    STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
    887    STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
    888 
    889 
    890    // @TODO: don't expose this structure
    891    typedef struct
    892    {
    893       int w, h, stride;
    894       unsigned char *pixels;
    895    } stbtt__bitmap;
    896 
    897    // rasterize a shape with quadratic beziers into a bitmap
    898    STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into
    899       float flatness_in_pixels,     // allowable error of curve in pixels
    900       stbtt_vertex *vertices,       // array of vertices defining shape
    901       int num_verts,                // number of vertices in above array
    902       float scale_x, float scale_y, // scale applied to input vertices
    903       float shift_x, float shift_y, // translation applied to input vertices
    904       int x_off, int y_off,         // another translation applied to input
    905       int invert,                   // if non-zero, vertically flip shape
    906       void *userdata);              // context for to STBTT_MALLOC
    907 
    908                                     //////////////////////////////////////////////////////////////////////////////
    909                                     //
    910                                     // Signed Distance Function (or Field) rendering
    911 
    912    STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
    913    // frees the SDF bitmap allocated below
    914 
    915    STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
    916    STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
    917    // These functions compute a discretized SDF field for a single character, suitable for storing
    918    // in a single-channel texture, sampling with bilinear filtering, and testing against
    919    // larger than some threshhold to produce scalable fonts.
    920    //        info              --  the font
    921    //        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
    922    //        glyph/codepoint   --  the character to generate the SDF for
    923    //        padding           --  extra "pixels" around the character which are filled with the distance to the character (not 0),
    924    //                                 which allows effects like bit outlines
    925    //        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
    926    //        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
    927    //                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside
    928    //        width,height      --  output height & width of the SDF bitmap (including padding)
    929    //        xoff,yoff         --  output origin of the character
    930    //        return value      --  a 2D array of bytes 0..255, width*height in size
    931    //
    932    // pixel_dist_scale & onedge_value are a scale & bias that allows you to make
    933    // optimal use of the limited 0..255 for your application, trading off precision
    934    // and special effects. SDF values outside the range 0..255 are clamped to 0..255.
    935    //
    936    // Example:
    937    //      scale = stbtt_ScaleForPixelHeight(22)
    938    //      padding = 5
    939    //      onedge_value = 180
    940    //      pixel_dist_scale = 180/5.0 = 36.0
    941    //
    942    //      This will create an SDF bitmap in which the character is about 22 pixels
    943    //      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
    944    //      shape, sample the SDF at each pixel and fill the pixel if the SDF value
    945    //      is greater than or equal to 180/255. (You'll actually want to antialias,
    946    //      which is beyond the scope of this example.) Additionally, you can compute
    947    //      offset outlines (e.g. to stroke the character border inside & outside,
    948    //      or only outside). For example, to fill outside the character up to 3 SDF
    949    //      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
    950    //      choice of variables maps a range from 5 pixels outside the shape to
    951    //      2 pixels inside the shape to 0..255; this is intended primarily for apply
    952    //      outside effects only (the interior range is needed to allow proper
    953    //      antialiasing of the font at *smaller* sizes)
    954    //
    955    // The function computes the SDF analytically at each SDF pixel, not by e.g.
    956    // building a higher-res bitmap and approximating it. In theory the quality
    957    // should be as high as possible for an SDF of this size & representation, but
    958    // unclear if this is true in practice (perhaps building a higher-res bitmap
    959    // and computing from that can allow drop-out prevention).
    960    //
    961    // The algorithm has not been optimized at all, so expect it to be slow
    962    // if computing lots of characters or very large sizes.
    963 
    964 
    965 
    966    //////////////////////////////////////////////////////////////////////////////
    967    //
    968    // Finding the right font...
    969    //
    970    // You should really just solve this offline, keep your own tables
    971    // of what font is what, and don't try to get it out of the .ttf file.
    972    // That's because getting it out of the .ttf file is really hard, because
    973    // the names in the file can appear in many possible encodings, in many
    974    // possible languages, and e.g. if you need a case-insensitive comparison,
    975    // the details of that depend on the encoding & language in a complex way
    976    // (actually underspecified in truetype, but also gigantic).
    977    //
    978    // But you can use the provided functions in two possible ways:
    979    //     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
    980    //             unicode-encoded names to try to find the font you want;
    981    //             you can run this before calling stbtt_InitFont()
    982    //
    983    //     stbtt_GetFontNameString() lets you get any of the various strings
    984    //             from the file yourself and do your own comparisons on them.
    985    //             You have to have called stbtt_InitFont() first.
    986 
    987 
    988    STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
    989    // returns the offset (not index) of the font that matches, or -1 if none
    990    //   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
    991    //   if you use any other flag, use a font name like "Arial"; this checks
    992    //     the 'macStyle' header field; i don't know if fonts set this consistently
     831STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);
     832// returns non-zero if nothing is drawn for this glyph
     833
     834STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);
     835STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);
     836// returns # of vertices and fills *vertices with the pointer to them
     837//   these are expressed in "unscaled" coordinates
     838//
     839// The shape is a series of contours. Each one starts with
     840// a STBTT_moveto, then consists of a series of mixed
     841// STBTT_lineto and STBTT_curveto segments. A lineto
     842// draws a line from previous endpoint to its x,y; a curveto
     843// draws a quadratic bezier from previous endpoint to
     844// its x,y, using cx,cy as the bezier control point.
     845
     846STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
     847// frees the data allocated above
     848
     849//////////////////////////////////////////////////////////////////////////////
     850//
     851// BITMAP RENDERING
     852//
     853
     854STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);
     855// frees the bitmap allocated below
     856
     857STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
     858// allocates a large-enough single-channel 8bpp bitmap and renders the
     859// specified character/glyph at the specified scale into it, with
     860// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).
     861// *width & *height are filled out with the width & height of the bitmap,
     862// which is stored left-to-right, top-to-bottom.
     863//
     864// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap
     865
     866STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);
     867// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel
     868// shift for the character
     869
     870STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);
     871// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap
     872// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap
     873// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the
     874// width and height and positioning info for it first.
     875
     876STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);
     877// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
     878// shift for the character
     879
     880STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
     881// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
     882// is performed (see stbtt_PackSetOversampling)
     883
     884STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
     885// get the bbox of the bitmap centered around the glyph origin; so the
     886// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
     887// the bitmap top left is (leftSideBearing*scale,iy0).
     888// (Note that the bitmap uses y-increases-down, but the shape uses
     889// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)
     890
     891STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
     892// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel
     893// shift for the character
     894
     895// the following functions are equivalent to the above functions, but operate
     896// on glyph indices instead of Unicode codepoints (for efficiency)
     897STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);
     898STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
     899STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
     900STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
     901STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
     902STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
     903STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
     904
     905
     906// @TODO: don't expose this structure
     907typedef struct
     908{
     909   int w,h,stride;
     910   unsigned char *pixels;
     911} stbtt__bitmap;
     912
     913// rasterize a shape with quadratic beziers into a bitmap
     914STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into
     915                               float flatness_in_pixels,     // allowable error of curve in pixels
     916                               stbtt_vertex *vertices,       // array of vertices defining shape
     917                               int num_verts,                // number of vertices in above array
     918                               float scale_x, float scale_y, // scale applied to input vertices
     919                               float shift_x, float shift_y, // translation applied to input vertices
     920                               int x_off, int y_off,         // another translation applied to input
     921                               int invert,                   // if non-zero, vertically flip shape
     922                               void *userdata);              // context for to STBTT_MALLOC
     923
     924//////////////////////////////////////////////////////////////////////////////
     925//
     926// Signed Distance Function (or Field) rendering
     927
     928STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
     929// frees the SDF bitmap allocated below
     930
     931STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
     932STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
     933// These functions compute a discretized SDF field for a single character, suitable for storing
     934// in a single-channel texture, sampling with bilinear filtering, and testing against
     935// larger than some threshold to produce scalable fonts.
     936//        info              --  the font
     937//        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
     938//        glyph/codepoint   --  the character to generate the SDF for
     939//        padding           --  extra "pixels" around the character which are filled with the distance to the character (not 0),
     940//                                 which allows effects like bit outlines
     941//        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
     942//        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
     943//                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside
     944//        width,height      --  output height & width of the SDF bitmap (including padding)
     945//        xoff,yoff         --  output origin of the character
     946//        return value      --  a 2D array of bytes 0..255, width*height in size
     947//
     948// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
     949// optimal use of the limited 0..255 for your application, trading off precision
     950// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
     951//
     952// Example:
     953//      scale = stbtt_ScaleForPixelHeight(22)
     954//      padding = 5
     955//      onedge_value = 180
     956//      pixel_dist_scale = 180/5.0 = 36.0
     957//
     958//      This will create an SDF bitmap in which the character is about 22 pixels
     959//      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
     960//      shape, sample the SDF at each pixel and fill the pixel if the SDF value
     961//      is greater than or equal to 180/255. (You'll actually want to antialias,
     962//      which is beyond the scope of this example.) Additionally, you can compute
     963//      offset outlines (e.g. to stroke the character border inside & outside,
     964//      or only outside). For example, to fill outside the character up to 3 SDF
     965//      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
     966//      choice of variables maps a range from 5 pixels outside the shape to
     967//      2 pixels inside the shape to 0..255; this is intended primarily for apply
     968//      outside effects only (the interior range is needed to allow proper
     969//      antialiasing of the font at *smaller* sizes)
     970//
     971// The function computes the SDF analytically at each SDF pixel, not by e.g.
     972// building a higher-res bitmap and approximating it. In theory the quality
     973// should be as high as possible for an SDF of this size & representation, but
     974// unclear if this is true in practice (perhaps building a higher-res bitmap
     975// and computing from that can allow drop-out prevention).
     976//
     977// The algorithm has not been optimized at all, so expect it to be slow
     978// if computing lots of characters or very large sizes.
     979
     980
     981
     982//////////////////////////////////////////////////////////////////////////////
     983//
     984// Finding the right font...
     985//
     986// You should really just solve this offline, keep your own tables
     987// of what font is what, and don't try to get it out of the .ttf file.
     988// That's because getting it out of the .ttf file is really hard, because
     989// the names in the file can appear in many possible encodings, in many
     990// possible languages, and e.g. if you need a case-insensitive comparison,
     991// the details of that depend on the encoding & language in a complex way
     992// (actually underspecified in truetype, but also gigantic).
     993//
     994// But you can use the provided functions in two possible ways:
     995//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on
     996//             unicode-encoded names to try to find the font you want;
     997//             you can run this before calling stbtt_InitFont()
     998//
     999//     stbtt_GetFontNameString() lets you get any of the various strings
     1000//             from the file yourself and do your own comparisons on them.
     1001//             You have to have called stbtt_InitFont() first.
     1002
     1003
     1004STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);
     1005// returns the offset (not index) of the font that matches, or -1 if none
     1006//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".
     1007//   if you use any other flag, use a font name like "Arial"; this checks
     1008//     the 'macStyle' header field; i don't know if fonts set this consistently
    9931009#define STBTT_MACSTYLE_DONTCARE     0
    9941010#define STBTT_MACSTYLE_BOLD         1
     
    9971013#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0
    9981014
    999    STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
    1000    // returns 1/0 whether the first string interpreted as utf8 is identical to
    1001    // the second string interpreted as big-endian utf16... useful for strings from next func
    1002 
    1003    STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
    1004    // returns the string (which may be big-endian double byte, e.g. for unicode)
    1005    // and puts the length in bytes in *length.
    1006    //
    1007    // some of the values for the IDs are below; for more see the truetype spec:
    1008    //     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
    1009    //     http://www.microsoft.com/typography/otspec/name.htm
    1010 
    1011    enum { // platformID
    1012       STBTT_PLATFORM_ID_UNICODE = 0,
    1013       STBTT_PLATFORM_ID_MAC = 1,
    1014       STBTT_PLATFORM_ID_ISO = 2,
    1015       STBTT_PLATFORM_ID_MICROSOFT = 3
    1016    };
    1017 
    1018    enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
    1019       STBTT_UNICODE_EID_UNICODE_1_0 = 0,
    1020       STBTT_UNICODE_EID_UNICODE_1_1 = 1,
    1021       STBTT_UNICODE_EID_ISO_10646 = 2,
    1022       STBTT_UNICODE_EID_UNICODE_2_0_BMP = 3,
    1023       STBTT_UNICODE_EID_UNICODE_2_0_FULL = 4
    1024    };
    1025 
    1026    enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
    1027       STBTT_MS_EID_SYMBOL = 0,
    1028       STBTT_MS_EID_UNICODE_BMP = 1,
    1029       STBTT_MS_EID_SHIFTJIS = 2,
    1030       STBTT_MS_EID_UNICODE_FULL = 10
    1031    };
    1032 
    1033    enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
    1034       STBTT_MAC_EID_ROMAN = 0, STBTT_MAC_EID_ARABIC = 4,
    1035       STBTT_MAC_EID_JAPANESE = 1, STBTT_MAC_EID_HEBREW = 5,
    1036       STBTT_MAC_EID_CHINESE_TRAD = 2, STBTT_MAC_EID_GREEK = 6,
    1037       STBTT_MAC_EID_KOREAN = 3, STBTT_MAC_EID_RUSSIAN = 7
    1038    };
    1039 
    1040    enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
    1041           // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
    1042       STBTT_MS_LANG_ENGLISH = 0x0409, STBTT_MS_LANG_ITALIAN = 0x0410,
    1043       STBTT_MS_LANG_CHINESE = 0x0804, STBTT_MS_LANG_JAPANESE = 0x0411,
    1044       STBTT_MS_LANG_DUTCH = 0x0413, STBTT_MS_LANG_KOREAN = 0x0412,
    1045       STBTT_MS_LANG_FRENCH = 0x040c, STBTT_MS_LANG_RUSSIAN = 0x0419,
    1046       STBTT_MS_LANG_GERMAN = 0x0407, STBTT_MS_LANG_SPANISH = 0x0409,
    1047       STBTT_MS_LANG_HEBREW = 0x040d, STBTT_MS_LANG_SWEDISH = 0x041D
    1048    };
    1049 
    1050    enum { // languageID for STBTT_PLATFORM_ID_MAC
    1051       STBTT_MAC_LANG_ENGLISH = 0, STBTT_MAC_LANG_JAPANESE = 11,
    1052       STBTT_MAC_LANG_ARABIC = 12, STBTT_MAC_LANG_KOREAN = 23,
    1053       STBTT_MAC_LANG_DUTCH = 4, STBTT_MAC_LANG_RUSSIAN = 32,
    1054       STBTT_MAC_LANG_FRENCH = 1, STBTT_MAC_LANG_SPANISH = 6,
    1055       STBTT_MAC_LANG_GERMAN = 2, STBTT_MAC_LANG_SWEDISH = 5,
    1056       STBTT_MAC_LANG_HEBREW = 10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED = 33,
    1057       STBTT_MAC_LANG_ITALIAN = 3, STBTT_MAC_LANG_CHINESE_TRAD = 19
    1058    };
     1015STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);
     1016// returns 1/0 whether the first string interpreted as utf8 is identical to
     1017// the second string interpreted as big-endian utf16... useful for strings from next func
     1018
     1019STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);
     1020// returns the string (which may be big-endian double byte, e.g. for unicode)
     1021// and puts the length in bytes in *length.
     1022//
     1023// some of the values for the IDs are below; for more see the truetype spec:
     1024//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
     1025//     http://www.microsoft.com/typography/otspec/name.htm
     1026
     1027enum { // platformID
     1028   STBTT_PLATFORM_ID_UNICODE   =0,
     1029   STBTT_PLATFORM_ID_MAC       =1,
     1030   STBTT_PLATFORM_ID_ISO       =2,
     1031   STBTT_PLATFORM_ID_MICROSOFT =3
     1032};
     1033
     1034enum { // encodingID for STBTT_PLATFORM_ID_UNICODE
     1035   STBTT_UNICODE_EID_UNICODE_1_0    =0,
     1036   STBTT_UNICODE_EID_UNICODE_1_1    =1,
     1037   STBTT_UNICODE_EID_ISO_10646      =2,
     1038   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,
     1039   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4
     1040};
     1041
     1042enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT
     1043   STBTT_MS_EID_SYMBOL        =0,
     1044   STBTT_MS_EID_UNICODE_BMP   =1,
     1045   STBTT_MS_EID_SHIFTJIS      =2,
     1046   STBTT_MS_EID_UNICODE_FULL  =10
     1047};
     1048
     1049enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes
     1050   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,
     1051   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,
     1052   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,
     1053   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7
     1054};
     1055
     1056enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...
     1057       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs
     1058   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,
     1059   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,
     1060   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,
     1061   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,
     1062   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,
     1063   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D
     1064};
     1065
     1066enum { // languageID for STBTT_PLATFORM_ID_MAC
     1067   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,
     1068   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,
     1069   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,
     1070   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,
     1071   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,
     1072   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,
     1073   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19
     1074};
    10591075
    10601076#ifdef __cplusplus
     
    10811097#endif
    10821098
    1083 typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE - 1)) == 0 ? 1 : -1];
     1099typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];
    10841100
    10851101#ifndef STBTT_RASTERIZER_VERSION
     
    11371153   stbtt__buf r;
    11381154   STBTT_assert(size < 0x40000000);
    1139    r.data = (stbtt_uint8*)p;
    1140    r.size = (int)size;
     1155   r.data = (stbtt_uint8*) p;
     1156   r.size = (int) size;
    11411157   r.cursor = 0;
    11421158   return r;
     
    11731189   int b0 = stbtt__buf_get8(b);
    11741190   if (b0 >= 32 && b0 <= 246)       return b0 - 139;
    1175    else if (b0 >= 247 && b0 <= 250) return (b0 - 247) * 256 + stbtt__buf_get8(b) + 108;
    1176    else if (b0 >= 251 && b0 <= 254) return -(b0 - 251) * 256 - stbtt__buf_get8(b) - 108;
     1191   else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
     1192   else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
    11771193   else if (b0 == 28)               return stbtt__buf_get16(b);
    11781194   else if (b0 == 29)               return stbtt__buf_get32(b);
     
    11911207            break;
    11921208      }
    1193    }
    1194    else {
     1209   } else {
    11951210      stbtt__cff_int(b);
    11961211   }
     
    12071222      op = stbtt__buf_get8(b);
    12081223      if (op == 12)  op = stbtt__buf_get8(b) | 0x100;
    1209       if (op == key) return stbtt__buf_range(b, start, end - start);
     1224      if (op == key) return stbtt__buf_range(b, start, end-start);
    12101225   }
    12111226   return stbtt__buf_range(b, 0, 0);
     
    12371252   start = stbtt__buf_get(&b, offsize);
    12381253   end = stbtt__buf_get(&b, offsize);
    1239    return stbtt__buf_range(&b, 2 + (count + 1)*offsize + start, end - start);
     1254   return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
    12401255}
    12411256
     
    12521267#define ttFixed(p)    ttLONG(p)
    12531268
    1254 static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0] * 256 + p[1]; }
    1255 static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0] * 256 + p[1]; }
    1256 static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; }
    1257 static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; }
     1269static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
     1270static stbtt_int16 ttSHORT(stbtt_uint8 *p)   { return p[0]*256 + p[1]; }
     1271static stbtt_uint32 ttULONG(stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
     1272static stbtt_int32 ttLONG(stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
    12581273
    12591274#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
     
    12631278{
    12641279   // check the version number
    1265    if (stbtt_tag4(font, '1', 0, 0, 0))  return 1; // TrueType 1
     1280   if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1
    12661281   if (stbtt_tag(font, "typ1"))   return 1; // TrueType with type 1 font -- we don't support this!
    12671282   if (stbtt_tag(font, "OTTO"))   return 1; // OpenType with CFF
    1268    if (stbtt_tag4(font, 0, 1, 0, 0)) return 1; // OpenType 1.0
     1283   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
    12691284   if (stbtt_tag(font, "true"))   return 1; // Apple specification for TrueType fonts
    12701285   return 0;
     
    12741289static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)
    12751290{
    1276    stbtt_int32 num_tables = ttUSHORT(data + fontstart + 4);
     1291   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);
    12771292   stbtt_uint32 tabledir = fontstart + 12;
    12781293   stbtt_int32 i;
    1279    for (i = 0; i < num_tables; ++i) {
    1280       stbtt_uint32 loc = tabledir + 16 * i;
    1281       if (stbtt_tag(data + loc + 0, tag))
    1282          return ttULONG(data + loc + 8);
     1294   for (i=0; i < num_tables; ++i) {
     1295      stbtt_uint32 loc = tabledir + 16*i;
     1296      if (stbtt_tag(data+loc+0, tag))
     1297         return ttULONG(data+loc+8);
    12831298   }
    12841299   return 0;
     
    12941309   if (stbtt_tag(font_collection, "ttcf")) {
    12951310      // version 1?
    1296       if (ttULONG(font_collection + 4) == 0x00010000 || ttULONG(font_collection + 4) == 0x00020000) {
    1297          stbtt_int32 n = ttLONG(font_collection + 8);
     1311      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
     1312         stbtt_int32 n = ttLONG(font_collection+8);
    12981313         if (index >= n)
    12991314            return -1;
    1300          return ttULONG(font_collection + 12 + index * 4);
     1315         return ttULONG(font_collection+12+index*4);
    13011316      }
    13021317   }
     
    13131328   if (stbtt_tag(font_collection, "ttcf")) {
    13141329      // version 1?
    1315       if (ttULONG(font_collection + 4) == 0x00010000 || ttULONG(font_collection + 4) == 0x00020000) {
    1316          return ttLONG(font_collection + 8);
     1330      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
     1331         return ttLONG(font_collection+8);
    13171332      }
    13181333   }
     
    13291344   stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
    13301345   if (!subrsoff) return stbtt__new_buf(NULL, 0);
    1331    stbtt__buf_seek(&cff, private_loc[1] + subrsoff);
     1346   stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
    13321347   return stbtt__cff_get_index(&cff);
    13331348}
     
    13361351{
    13371352   stbtt_uint32 cmap, t;
    1338    stbtt_int32 i, numTables;
     1353   stbtt_int32 i,numTables;
    13391354
    13401355   info->data = data;
     
    13561371      // required for truetype
    13571372      if (!info->loca) return 0;
    1358    }
    1359    else {
     1373   } else {
    13601374      // initialization for CFF / Type2 fonts (OTF)
    13611375      stbtt__buf b, topdict, topdictidx;
     
    13701384
    13711385      // @TODO this should use size from table (not 512MB)
    1372       info->cff = stbtt__new_buf(data + cff, 512 * 1024 * 1024);
     1386      info->cff = stbtt__new_buf(data+cff, 512*1024*1024);
    13731387      b = info->cff;
    13741388
     
    13771391      stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
    13781392
    1379                                                 // @TODO the name INDEX could list multiple fonts,
    1380                                                 // but we just use the first one.
     1393      // @TODO the name INDEX could list multiple fonts,
     1394      // but we just use the first one.
    13811395      stbtt__cff_get_index(&b);  // name INDEX
    13821396      topdictidx = stbtt__cff_get_index(&b);
     
    14001414         stbtt__buf_seek(&b, fdarrayoff);
    14011415         info->fontdicts = stbtt__cff_get_index(&b);
    1402          info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size - fdselectoff);
     1416         info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
    14031417      }
    14041418
     
    14091423   t = stbtt__find_table(data, fontstart, "maxp");
    14101424   if (t)
    1411       info->numGlyphs = ttUSHORT(data + t + 4);
     1425      info->numGlyphs = ttUSHORT(data+t+4);
    14121426   else
    14131427      info->numGlyphs = 0xffff;
     
    14181432   numTables = ttUSHORT(data + cmap + 2);
    14191433   info->index_map = 0;
    1420    for (i = 0; i < numTables; ++i) {
     1434   for (i=0; i < numTables; ++i) {
    14211435      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;
    14221436      // find an encoding we understand:
    1423       switch (ttUSHORT(data + encoding_record)) {
    1424       case STBTT_PLATFORM_ID_MICROSOFT:
    1425          switch (ttUSHORT(data + encoding_record + 2)) {
    1426          case STBTT_MS_EID_UNICODE_BMP:
    1427          case STBTT_MS_EID_UNICODE_FULL:
    1428             // MS/Unicode
    1429             info->index_map = cmap + ttULONG(data + encoding_record + 4);
     1437      switch(ttUSHORT(data+encoding_record)) {
     1438         case STBTT_PLATFORM_ID_MICROSOFT:
     1439            switch (ttUSHORT(data+encoding_record+2)) {
     1440               case STBTT_MS_EID_UNICODE_BMP:
     1441               case STBTT_MS_EID_UNICODE_FULL:
     1442                  // MS/Unicode
     1443                  info->index_map = cmap + ttULONG(data+encoding_record+4);
     1444                  break;
     1445            }
    14301446            break;
    1431          }
    1432          break;
    1433       case STBTT_PLATFORM_ID_UNICODE:
    1434          // Mac/iOS has these
    1435          // all the encodingIDs are unicode, so we don't bother to check it
    1436          info->index_map = cmap + ttULONG(data + encoding_record + 4);
    1437          break;
     1447        case STBTT_PLATFORM_ID_UNICODE:
     1448            // Mac/iOS has these
     1449            // all the encodingIDs are unicode, so we don't bother to check it
     1450            info->index_map = cmap + ttULONG(data+encoding_record+4);
     1451            break;
    14381452      }
    14391453   }
     
    14411455      return 0;
    14421456
    1443    info->indexToLocFormat = ttUSHORT(data + info->head + 50);
     1457   info->indexToLocFormat = ttUSHORT(data+info->head + 50);
    14441458   return 1;
    14451459}
     
    14531467   if (format == 0) { // apple byte encoding
    14541468      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);
    1455       if (unicode_codepoint < bytes - 6)
     1469      if (unicode_codepoint < bytes-6)
    14561470         return ttBYTE(data + index_map + 6 + unicode_codepoint);
    14571471      return 0;
    1458    }
    1459    else if (format == 6) {
     1472   } else if (format == 6) {
    14601473      stbtt_uint32 first = ttUSHORT(data + index_map + 6);
    14611474      stbtt_uint32 count = ttUSHORT(data + index_map + 8);
    1462       if ((stbtt_uint32)unicode_codepoint >= first && (stbtt_uint32)unicode_codepoint < first + count)
    1463          return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first) * 2);
     1475      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)
     1476         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);
    14641477      return 0;
    1465    }
    1466    else if (format == 2) {
     1478   } else if (format == 2) {
    14671479      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean
    14681480      return 0;
    1469    }
    1470    else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
    1471       stbtt_uint16 segcount = ttUSHORT(data + index_map + 6) >> 1;
    1472       stbtt_uint16 searchRange = ttUSHORT(data + index_map + 8) >> 1;
    1473       stbtt_uint16 entrySelector = ttUSHORT(data + index_map + 10);
    1474       stbtt_uint16 rangeShift = ttUSHORT(data + index_map + 12) >> 1;
     1481   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges
     1482      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;
     1483      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;
     1484      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);
     1485      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;
    14751486
    14761487      // do a binary search of the segments
     
    14831494      // they lie from endCount .. endCount + segCount
    14841495      // but searchRange is the nearest power of two, so...
    1485       if (unicode_codepoint >= ttUSHORT(data + search + rangeShift * 2))
    1486          search += rangeShift * 2;
     1496      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))
     1497         search += rangeShift*2;
    14871498
    14881499      // now decrement to bias correctly to find smallest
     
    14911502         stbtt_uint16 end;
    14921503         searchRange >>= 1;
    1493          end = ttUSHORT(data + search + searchRange * 2);
     1504         end = ttUSHORT(data + search + searchRange*2);
    14941505         if (unicode_codepoint > end)
    1495             search += searchRange * 2;
     1506            search += searchRange*2;
    14961507         --entrySelector;
    14971508      }
     
    15001511      {
    15011512         stbtt_uint16 offset, start;
    1502          stbtt_uint16 item = (stbtt_uint16)((search - endCount) >> 1);
    1503 
    1504          STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2 * item));
    1505          start = ttUSHORT(data + index_map + 14 + segcount * 2 + 2 + 2 * item);
     1513         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
     1514
     1515         STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
     1516         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
    15061517         if (unicode_codepoint < start)
    15071518            return 0;
    15081519
    1509          offset = ttUSHORT(data + index_map + 14 + segcount * 6 + 2 + 2 * item);
     1520         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
    15101521         if (offset == 0)
    1511             return (stbtt_uint16)(unicode_codepoint + ttSHORT(data + index_map + 14 + segcount * 4 + 2 + 2 * item));
    1512 
    1513          return ttUSHORT(data + offset + (unicode_codepoint - start) * 2 + index_map + 14 + segcount * 6 + 2 + 2 * item);
    1514       }
    1515    }
    1516    else if (format == 12 || format == 13) {
    1517       stbtt_uint32 ngroups = ttULONG(data + index_map + 12);
    1518       stbtt_int32 low, high;
     1522            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));
     1523
     1524         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);
     1525      }
     1526   } else if (format == 12 || format == 13) {
     1527      stbtt_uint32 ngroups = ttULONG(data+index_map+12);
     1528      stbtt_int32 low,high;
    15191529      low = 0; high = (stbtt_int32)ngroups;
    15201530      // Binary search the right group.
    15211531      while (low < high) {
    1522          stbtt_int32 mid = low + ((high - low) >> 1); // rounds down, so low <= mid < high
    1523          stbtt_uint32 start_char = ttULONG(data + index_map + 16 + mid * 12);
    1524          stbtt_uint32 end_char = ttULONG(data + index_map + 16 + mid * 12 + 4);
    1525          if ((stbtt_uint32)unicode_codepoint < start_char)
     1532         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high
     1533         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);
     1534         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);
     1535         if ((stbtt_uint32) unicode_codepoint < start_char)
    15261536            high = mid;
    1527          else if ((stbtt_uint32)unicode_codepoint > end_char)
    1528             low = mid + 1;
     1537         else if ((stbtt_uint32) unicode_codepoint > end_char)
     1538            low = mid+1;
    15291539         else {
    1530             stbtt_uint32 start_glyph = ttULONG(data + index_map + 16 + mid * 12 + 8);
     1540            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);
    15311541            if (format == 12)
    1532                return start_glyph + unicode_codepoint - start_char;
     1542               return start_glyph + unicode_codepoint-start_char;
    15331543            else // format == 13
    15341544               return start_glyph;
     
    15501560{
    15511561   v->type = type;
    1552    v->x = (stbtt_int16)x;
    1553    v->y = (stbtt_int16)y;
    1554    v->cx = (stbtt_int16)cx;
    1555    v->cy = (stbtt_int16)cy;
     1562   v->x = (stbtt_int16) x;
     1563   v->y = (stbtt_int16) y;
     1564   v->cx = (stbtt_int16) cx;
     1565   v->cy = (stbtt_int16) cy;
    15561566}
    15571567
    15581568static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
    15591569{
    1560    int g1, g2;
     1570   int g1,g2;
    15611571
    15621572   STBTT_assert(!info->cff.size);
     
    15681578      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;
    15691579      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;
    1570    }
    1571    else {
    1572       g1 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4);
    1573       g2 = info->glyf + ttULONG(info->data + info->loca + glyph_index * 4 + 4);
    1574    }
    1575 
    1576    return g1 == g2 ? -1 : g1; // if length is 0, return -1
     1580   } else {
     1581      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);
     1582      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);
     1583   }
     1584
     1585   return g1==g2 ? -1 : g1; // if length is 0, return -1
    15771586}
    15781587
     
    15831592   if (info->cff.size) {
    15841593      stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
    1585    }
    1586    else {
     1594   } else {
    15871595      int g = stbtt__GetGlyfOffset(info, glyph_index);
    15881596      if (g < 0) return 0;
     
    15981606STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)
    15991607{
    1600    return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info, codepoint), x0, y0, x1, y1);
     1608   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);
    16011609}
    16021610
     
    16141622
    16151623static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,
    1616    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
     1624    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)
    16171625{
    16181626   if (start_off) {
    16191627      if (was_off)
    1620          stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + scx) >> 1, (cy + scy) >> 1, cx, cy);
    1621       stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, scx, scy);
    1622    }
    1623    else {
     1628         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);
     1629      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);
     1630   } else {
    16241631      if (was_off)
    1625          stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx, sy, cx, cy);
     1632         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);
    16261633      else
    1627          stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, sx, sy, 0, 0);
     1634         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);
    16281635   }
    16291636   return num_vertices;
     
    16351642   stbtt_uint8 *endPtsOfContours;
    16361643   stbtt_uint8 *data = info->data;
    1637    stbtt_vertex *vertices = 0;
    1638    int num_vertices = 0;
     1644   stbtt_vertex *vertices=0;
     1645   int num_vertices=0;
    16391646   int g = stbtt__GetGlyfOffset(info, glyph_index);
    16401647
     
    16461653
    16471654   if (numberOfContours > 0) {
    1648       stbtt_uint8 flags = 0, flagcount;
    1649       stbtt_int32 ins, i, j = 0, m, n, next_move, was_off = 0, off, start_off = 0;
    1650       stbtt_int32 x, y, cx, cy, sx, sy, scx, scy;
     1655      stbtt_uint8 flags=0,flagcount;
     1656      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;
     1657      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;
    16511658      stbtt_uint8 *points;
    16521659      endPtsOfContours = (data + g + 10);
     
    16541661      points = data + g + 10 + numberOfContours * 2 + 2 + ins;
    16551662
    1656       n = 1 + ttUSHORT(endPtsOfContours + numberOfContours * 2 - 2);
    1657 
    1658       m = n + 2 * numberOfContours;  // a loose bound on how many vertices we might need
    1659       vertices = (stbtt_vertex *)STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
     1663      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);
     1664
     1665      m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need
     1666      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);
    16601667      if (vertices == 0)
    16611668         return 0;
    16621669
    16631670      next_move = 0;
    1664       flagcount = 0;
     1671      flagcount=0;
    16651672
    16661673      // in first pass, we load uninterpreted data into the allocated array
     
    16701677      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated
    16711678
    1672                    // first load flags
    1673 
    1674       for (i = 0; i < n; ++i) {
     1679      // first load flags
     1680
     1681      for (i=0; i < n; ++i) {
    16751682         if (flagcount == 0) {
    16761683            flags = *points++;
    16771684            if (flags & 8)
    16781685               flagcount = *points++;
    1679          }
    1680          else
     1686         } else
    16811687            --flagcount;
    1682          vertices[off + i].type = flags;
     1688         vertices[off+i].type = flags;
    16831689      }
    16841690
    16851691      // now load x coordinates
    1686       x = 0;
    1687       for (i = 0; i < n; ++i) {
    1688          flags = vertices[off + i].type;
     1692      x=0;
     1693      for (i=0; i < n; ++i) {
     1694         flags = vertices[off+i].type;
    16891695         if (flags & 2) {
    16901696            stbtt_int16 dx = *points++;
    16911697            x += (flags & 16) ? dx : -dx; // ???
    1692          }
    1693          else {
     1698         } else {
    16941699            if (!(flags & 16)) {
    1695                x = x + (stbtt_int16)(points[0] * 256 + points[1]);
     1700               x = x + (stbtt_int16) (points[0]*256 + points[1]);
    16961701               points += 2;
    16971702            }
    16981703         }
    1699          vertices[off + i].x = (stbtt_int16)x;
     1704         vertices[off+i].x = (stbtt_int16) x;
    17001705      }
    17011706
    17021707      // now load y coordinates
    1703       y = 0;
    1704       for (i = 0; i < n; ++i) {
    1705          flags = vertices[off + i].type;
     1708      y=0;
     1709      for (i=0; i < n; ++i) {
     1710         flags = vertices[off+i].type;
    17061711         if (flags & 4) {
    17071712            stbtt_int16 dy = *points++;
    17081713            y += (flags & 32) ? dy : -dy; // ???
    1709          }
    1710          else {
     1714         } else {
    17111715            if (!(flags & 32)) {
    1712                y = y + (stbtt_int16)(points[0] * 256 + points[1]);
     1716               y = y + (stbtt_int16) (points[0]*256 + points[1]);
    17131717               points += 2;
    17141718            }
    17151719         }
    1716          vertices[off + i].y = (stbtt_int16)y;
     1720         vertices[off+i].y = (stbtt_int16) y;
    17171721      }
    17181722
    17191723      // now convert them to our format
    1720       num_vertices = 0;
     1724      num_vertices=0;
    17211725      sx = sy = cx = cy = scx = scy = 0;
    1722       for (i = 0; i < n; ++i) {
    1723          flags = vertices[off + i].type;
    1724          x = (stbtt_int16)vertices[off + i].x;
    1725          y = (stbtt_int16)vertices[off + i].y;
     1726      for (i=0; i < n; ++i) {
     1727         flags = vertices[off+i].type;
     1728         x     = (stbtt_int16) vertices[off+i].x;
     1729         y     = (stbtt_int16) vertices[off+i].y;
    17261730
    17271731         if (next_move == i) {
    17281732            if (i != 0)
    1729                num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy);
     1733               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
    17301734
    17311735            // now start the new one               
     
    17361740               scx = x;
    17371741               scy = y;
    1738                if (!(vertices[off + i + 1].type & 1)) {
     1742               if (!(vertices[off+i+1].type & 1)) {
    17391743                  // next point is also a curve point, so interpolate an on-point curve
    1740                   sx = (x + (stbtt_int32)vertices[off + i + 1].x) >> 1;
    1741                   sy = (y + (stbtt_int32)vertices[off + i + 1].y) >> 1;
    1742                }
    1743                else {
     1744                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;
     1745                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;
     1746               } else {
    17441747                  // otherwise just use the next point as our start point
    1745                   sx = (stbtt_int32)vertices[off + i + 1].x;
    1746                   sy = (stbtt_int32)vertices[off + i + 1].y;
     1748                  sx = (stbtt_int32) vertices[off+i+1].x;
     1749                  sy = (stbtt_int32) vertices[off+i+1].y;
    17471750                  ++i; // we're using point i+1 as the starting point, so skip it
    17481751               }
    1749             }
    1750             else {
     1752            } else {
    17511753               sx = x;
    17521754               sy = y;
    17531755            }
    1754             stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove, sx, sy, 0, 0);
     1756            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);
    17551757            was_off = 0;
    1756             next_move = 1 + ttUSHORT(endPtsOfContours + j * 2);
     1758            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);
    17571759            ++j;
    1758          }
    1759          else {
     1760         } else {
    17601761            if (!(flags & 1)) { // if it's a curve
    17611762               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint
    1762                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx + x) >> 1, (cy + y) >> 1, cx, cy);
     1763                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);
    17631764               cx = x;
    17641765               cy = y;
    17651766               was_off = 1;
    1766             }
    1767             else {
     1767            } else {
    17681768               if (was_off)
    1769                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x, y, cx, cy);
     1769                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);
    17701770               else
    1771                   stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x, y, 0, 0);
     1771                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);
    17721772               was_off = 0;
    17731773            }
    17741774         }
    17751775      }
    1776       num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx, sy, scx, scy, cx, cy);
    1777    }
    1778    else if (numberOfContours == -1) {
     1776      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);
     1777   } else if (numberOfContours == -1) {
    17791778      // Compound shapes.
    17801779      int more = 1;
     
    17861785         int comp_num_verts = 0, i;
    17871786         stbtt_vertex *comp_verts = 0, *tmp = 0;
    1788          float mtx[6] = { 1,0,0,1,0,0 }, m, n;
    1789 
    1790          flags = ttSHORT(comp); comp += 2;
    1791          gidx = ttSHORT(comp); comp += 2;
     1787         float mtx[6] = {1,0,0,1,0,0}, m, n;
     1788         
     1789         flags = ttSHORT(comp); comp+=2;
     1790         gidx = ttSHORT(comp); comp+=2;
    17921791
    17931792         if (flags & 2) { // XY values
    17941793            if (flags & 1) { // shorts
    1795                mtx[4] = ttSHORT(comp); comp += 2;
    1796                mtx[5] = ttSHORT(comp); comp += 2;
    1797             }
    1798             else {
    1799                mtx[4] = ttCHAR(comp); comp += 1;
    1800                mtx[5] = ttCHAR(comp); comp += 1;
     1794               mtx[4] = ttSHORT(comp); comp+=2;
     1795               mtx[5] = ttSHORT(comp); comp+=2;
     1796            } else {
     1797               mtx[4] = ttCHAR(comp); comp+=1;
     1798               mtx[5] = ttCHAR(comp); comp+=1;
    18011799            }
    18021800         }
     
    18051803            STBTT_assert(0);
    18061804         }
    1807          if (flags & (1 << 3)) { // WE_HAVE_A_SCALE
    1808             mtx[0] = mtx[3] = ttSHORT(comp) / 16384.0f; comp += 2;
     1805         if (flags & (1<<3)) { // WE_HAVE_A_SCALE
     1806            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
    18091807            mtx[1] = mtx[2] = 0;
     1808         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE
     1809            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
     1810            mtx[1] = mtx[2] = 0;
     1811            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
     1812         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO
     1813            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;
     1814            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;
     1815            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;
     1816            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;
    18101817         }
    1811          else if (flags & (1 << 6)) { // WE_HAVE_AN_X_AND_YSCALE
    1812             mtx[0] = ttSHORT(comp) / 16384.0f; comp += 2;
    1813             mtx[1] = mtx[2] = 0;
    1814             mtx[3] = ttSHORT(comp) / 16384.0f; comp += 2;
    1815          }
    1816          else if (flags & (1 << 7)) { // WE_HAVE_A_TWO_BY_TWO
    1817             mtx[0] = ttSHORT(comp) / 16384.0f; comp += 2;
    1818             mtx[1] = ttSHORT(comp) / 16384.0f; comp += 2;
    1819             mtx[2] = ttSHORT(comp) / 16384.0f; comp += 2;
    1820             mtx[3] = ttSHORT(comp) / 16384.0f; comp += 2;
    1821          }
    1822 
     1818         
    18231819         // Find transformation scales.
    1824          m = (float)STBTT_sqrt(mtx[0] * mtx[0] + mtx[1] * mtx[1]);
    1825          n = (float)STBTT_sqrt(mtx[2] * mtx[2] + mtx[3] * mtx[3]);
     1820         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);
     1821         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);
    18261822
    18271823         // Get indexed glyph.
     
    18311827            for (i = 0; i < comp_num_verts; ++i) {
    18321828               stbtt_vertex* v = &comp_verts[i];
    1833                stbtt_vertex_type x, y;
    1834                x = v->x; y = v->y;
    1835                v->x = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4]));
    1836                v->y = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5]));
    1837                x = v->cx; y = v->cy;
    1838                v->cx = (stbtt_vertex_type)(m * (mtx[0] * x + mtx[2] * y + mtx[4]));
    1839                v->cy = (stbtt_vertex_type)(n * (mtx[1] * x + mtx[3] * y + mtx[5]));
     1829               stbtt_vertex_type x,y;
     1830               x=v->x; y=v->y;
     1831               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
     1832               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
     1833               x=v->cx; y=v->cy;
     1834               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));
     1835               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));
    18401836            }
    18411837            // Append vertices.
    1842             tmp = (stbtt_vertex*)STBTT_malloc((num_vertices + comp_num_verts) * sizeof(stbtt_vertex), info->userdata);
     1838            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);
    18431839            if (!tmp) {
    18441840               if (vertices) STBTT_free(vertices, info->userdata);
     
    18461842               return 0;
    18471843            }
    1848             if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices * sizeof(stbtt_vertex));
    1849             STBTT_memcpy(tmp + num_vertices, comp_verts, comp_num_verts * sizeof(stbtt_vertex));
     1844            if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); //-V595
     1845            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
    18501846            if (vertices) STBTT_free(vertices, info->userdata);
    18511847            vertices = tmp;
     
    18541850         }
    18551851         // More components ?
    1856          more = flags & (1 << 5);
    1857       }
    1858    }
    1859    else if (numberOfContours < 0) {
     1852         more = flags & (1<<5);
     1853      }
     1854   } else if (numberOfContours < 0) {
    18601855      // @TODO other compound variations?
    18611856      STBTT_assert(0);
    1862    }
    1863    else {
     1857   } else {
    18641858      // numberOfCounters == 0, do nothing
    18651859   }
     
    19001894         stbtt__track_vertex(c, cx1, cy1);
    19011895      }
    1902    }
    1903    else {
     1896   } else {
    19041897      stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
    1905       c->pvertices[c->num_vertices].cx1 = (stbtt_int16)cx1;
    1906       c->pvertices[c->num_vertices].cy1 = (stbtt_int16)cy1;
     1898      c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;
     1899      c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;
    19071900   }
    19081901   c->num_vertices++;
     
    19661959      stbtt__buf_skip(&fdselect, glyph_index);
    19671960      fdselector = stbtt__buf_get8(&fdselect);
    1968    }
    1969    else if (fmt == 3) {
     1961   } else if (fmt == 3) {
    19701962      nranges = stbtt__buf_get16(&fdselect);
    19711963      start = stbtt__buf_get16(&fdselect);
     
    20011993      b0 = stbtt__buf_get8(&b);
    20021994      switch (b0) {
    2003          // @TODO implement hinting
     1995      // @TODO implement hinting
    20041996      case 0x13: // hintmask
    20051997      case 0x14: // cntrmask
     
    20202012         in_header = 0;
    20212013         if (sp < 2) return STBTT__CSERR("rmoveto stack");
    2022          stbtt__csctx_rmove_to(c, s[sp - 2], s[sp - 1]);
     2014         stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
    20232015         break;
    20242016      case 0x04: // vmoveto
    20252017         in_header = 0;
    20262018         if (sp < 1) return STBTT__CSERR("vmoveto stack");
    2027          stbtt__csctx_rmove_to(c, 0, s[sp - 1]);
     2019         stbtt__csctx_rmove_to(c, 0, s[sp-1]);
    20282020         break;
    20292021      case 0x16: // hmoveto
    20302022         in_header = 0;
    20312023         if (sp < 1) return STBTT__CSERR("hmoveto stack");
    2032          stbtt__csctx_rmove_to(c, s[sp - 1], 0);
     2024         stbtt__csctx_rmove_to(c, s[sp-1], 0);
    20332025         break;
    20342026
     
    20362028         if (sp < 2) return STBTT__CSERR("rlineto stack");
    20372029         for (; i + 1 < sp; i += 2)
    2038             stbtt__csctx_rline_to(c, s[i], s[i + 1]);
     2030            stbtt__csctx_rline_to(c, s[i], s[i+1]);
    20392031         break;
    20402032
    2041          // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
    2042          // starting from a different place.
     2033      // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
     2034      // starting from a different place.
    20432035
    20442036      case 0x07: // vlineto
     
    20512043            stbtt__csctx_rline_to(c, s[i], 0);
    20522044            i++;
    2053          vlineto:
     2045      vlineto:
    20542046            if (i >= sp) break;
    20552047            stbtt__csctx_rline_to(c, 0, s[i]);
     
    20652057         for (;;) {
    20662058            if (i + 3 >= sp) break;
    2067             stbtt__csctx_rccurve_to(c, 0, s[i], s[i + 1], s[i + 2], s[i + 3], (sp - i == 5) ? s[i + 4] : 0.0f);
     2059            stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);
    20682060            i += 4;
    2069          hvcurveto:
     2061      hvcurveto:
    20702062            if (i + 3 >= sp) break;
    2071             stbtt__csctx_rccurve_to(c, s[i], 0, s[i + 1], s[i + 2], (sp - i == 5) ? s[i + 4] : 0.0f, s[i + 3]);
     2063            stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);
    20722064            i += 4;
    20732065         }
     
    20772069         if (sp < 6) return STBTT__CSERR("rcurveline stack");
    20782070         for (; i + 5 < sp; i += 6)
    2079             stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]);
     2071            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
    20802072         break;
    20812073
     
    20832075         if (sp < 8) return STBTT__CSERR("rcurveline stack");
    20842076         for (; i + 5 < sp - 2; i += 6)
    2085             stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]);
     2077            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
    20862078         if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
    2087          stbtt__csctx_rline_to(c, s[i], s[i + 1]);
     2079         stbtt__csctx_rline_to(c, s[i], s[i+1]);
    20882080         break;
    20892081
     
    20912083         if (sp < 8) return STBTT__CSERR("rlinecurve stack");
    20922084         for (; i + 1 < sp - 6; i += 2)
    2093             stbtt__csctx_rline_to(c, s[i], s[i + 1]);
     2085            stbtt__csctx_rline_to(c, s[i], s[i+1]);
    20942086         if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
    2095          stbtt__csctx_rccurve_to(c, s[i], s[i + 1], s[i + 2], s[i + 3], s[i + 4], s[i + 5]);
     2087         stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
    20962088         break;
    20972089
     
    21032095         for (; i + 3 < sp; i += 4) {
    21042096            if (b0 == 0x1B)
    2105                stbtt__csctx_rccurve_to(c, s[i], f, s[i + 1], s[i + 2], s[i + 3], 0.0);
     2097               stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
    21062098            else
    2107                stbtt__csctx_rccurve_to(c, f, s[i], s[i + 1], s[i + 2], 0.0, s[i + 3]);
     2099               stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
    21082100            f = 0.0;
    21092101         }
     
    21192111      case 0x1D: // callgsubr
    21202112         if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
    2121          v = (int)s[--sp];
     2113         v = (int) s[--sp];
    21222114         if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
    21232115         subr_stack[subr_stack_height++] = b;
     
    21432135         int b1 = stbtt__buf_get8(&b);
    21442136         switch (b1) {
    2145             // @TODO These "flex" implementations ignore the flex-depth and resolution,
    2146             // and always draw beziers.
     2137         // @TODO These "flex" implementations ignore the flex-depth and resolution,
     2138         // and always draw beziers.
    21472139         case 0x22: // hflex
    21482140            if (sp < 7) return STBTT__CSERR("hflex stack");
     
    21892181            dx6 = s[8];
    21902182            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
    2191             stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1 + dy2 + dy5));
     2183            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
    21922184            break;
    21932185
     
    22052197            dy5 = s[9];
    22062198            dx6 = dy6 = s[10];
    2207             dx = dx1 + dx2 + dx3 + dx4 + dx5;
    2208             dy = dy1 + dy2 + dy3 + dy4 + dy5;
     2199            dx = dx1+dx2+dx3+dx4+dx5;
     2200            dy = dy1+dy2+dy3+dy4+dy5;
    22092201            if (STBTT_fabs(dx) > STBTT_fabs(dy))
    22102202               dy6 = -dy;
     
    22212213
    22222214      default:
    2223          if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
     2215         if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254)) //-V560
    22242216            return STBTT__CSERR("reserved operator");
    22252217
     
    22272219         if (b0 == 255) {
    22282220            f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;
    2229          }
    2230          else {
     2221         } else {
    22312222            stbtt__buf_skip(&b, -1);
    22322223            f = (float)(stbtt_int16)stbtt__cff_int(&b);
     
    22502241   stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);
    22512242   if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
    2252       *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices * sizeof(stbtt_vertex), info->userdata);
     2243      *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);
    22532244      output_ctx.pvertices = *pvertices;
    22542245      if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
     
    22822273STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
    22832274{
    2284    stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data + info->hhea + 34);
     2275   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
    22852276   if (glyph_index < numOfLongHorMetrics) {
    2286       if (advanceWidth)     *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * glyph_index);
    2287       if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4 * glyph_index + 2);
    2288    }
    2289    else {
    2290       if (advanceWidth)     *advanceWidth = ttSHORT(info->data + info->hmtx + 4 * (numOfLongHorMetrics - 1));
    2291       if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4 * numOfLongHorMetrics + 2 * (glyph_index - numOfLongHorMetrics));
     2277      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);
     2278      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);
     2279   } else {
     2280      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));
     2281      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));
    22922282   }
    22932283}
     
    23022292   if (!info->kern)
    23032293      return 0;
    2304    if (ttUSHORT(data + 2) < 1) // number of tables, need at least 1
     2294   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1
    23052295      return 0;
    2306    if (ttUSHORT(data + 8) != 1) // horizontal flag must be set in format
     2296   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format
    23072297      return 0;
    23082298
    23092299   l = 0;
    2310    r = ttUSHORT(data + 10) - 1;
     2300   r = ttUSHORT(data+10) - 1;
    23112301   needle = glyph1 << 16 | glyph2;
    23122302   while (l <= r) {
    23132303      m = (l + r) >> 1;
    2314       straw = ttULONG(data + 18 + (m * 6)); // note: unaligned read
     2304      straw = ttULONG(data+18+(m*6)); // note: unaligned read
    23152305      if (needle < straw)
    23162306         r = m - 1;
     
    23182308         l = m + 1;
    23192309      else
    2320          return ttSHORT(data + 22 + (m * 6));
     2310         return ttSHORT(data+22+(m*6));
    23212311   }
    23222312   return 0;
     
    23252315static stbtt_int32  stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
    23262316{
    2327    stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
    2328    switch (coverageFormat) {
    2329    case 1: {
    2330       stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
    2331 
    2332       // Binary search.
    2333       stbtt_int32 l = 0, r = glyphCount - 1, m;
    2334       int straw, needle = glyph;
    2335       while (l <= r) {
    2336          stbtt_uint8 *glyphArray = coverageTable + 4;
    2337          stbtt_uint16 glyphID;
    2338          m = (l + r) >> 1;
    2339          glyphID = ttUSHORT(glyphArray + 2 * m);
    2340          straw = glyphID;
    2341          if (needle < straw)
    2342             r = m - 1;
    2343          else if (needle > straw)
    2344             l = m + 1;
    2345          else {
    2346             return m;
    2347          }
    2348       }
    2349    } break;
    2350 
    2351    case 2: {
    2352       stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
    2353       stbtt_uint8 *rangeArray = coverageTable + 4;
    2354 
    2355       // Binary search.
    2356       stbtt_int32 l = 0, r = rangeCount - 1, m;
    2357       int strawStart, strawEnd, needle = glyph;
    2358       while (l <= r) {
    2359          stbtt_uint8 *rangeRecord;
    2360          m = (l + r) >> 1;
    2361          rangeRecord = rangeArray + 6 * m;
    2362          strawStart = ttUSHORT(rangeRecord);
    2363          strawEnd = ttUSHORT(rangeRecord + 2);
    2364          if (needle < strawStart)
    2365             r = m - 1;
    2366          else if (needle > strawEnd)
    2367             l = m + 1;
    2368          else {
    2369             stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
    2370             return startCoverageIndex + glyph - strawStart;
    2371          }
    2372       }
    2373    } break;
    2374 
    2375    default: {
    2376       // There are no other cases.
    2377       STBTT_assert(0);
    2378    } break;
    2379    }
    2380 
    2381    return -1;
     2317    stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
     2318    switch(coverageFormat) {
     2319        case 1: {
     2320            stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
     2321
     2322            // Binary search.
     2323            stbtt_int32 l=0, r=glyphCount-1, m;
     2324            int straw, needle=glyph;
     2325            while (l <= r) {
     2326                stbtt_uint8 *glyphArray = coverageTable + 4;
     2327                stbtt_uint16 glyphID;
     2328                m = (l + r) >> 1;
     2329                glyphID = ttUSHORT(glyphArray + 2 * m);
     2330                straw = glyphID;
     2331                if (needle < straw)
     2332                    r = m - 1;
     2333                else if (needle > straw)
     2334                    l = m + 1;
     2335                else {
     2336                     return m;
     2337                }
     2338            }
     2339        } break;
     2340
     2341        case 2: {
     2342            stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
     2343            stbtt_uint8 *rangeArray = coverageTable + 4;
     2344
     2345            // Binary search.
     2346            stbtt_int32 l=0, r=rangeCount-1, m;
     2347            int strawStart, strawEnd, needle=glyph;
     2348            while (l <= r) {
     2349                stbtt_uint8 *rangeRecord;
     2350                m = (l + r) >> 1;
     2351                rangeRecord = rangeArray + 6 * m;
     2352                strawStart = ttUSHORT(rangeRecord);
     2353                strawEnd = ttUSHORT(rangeRecord + 2);
     2354                if (needle < strawStart)
     2355                    r = m - 1;
     2356                else if (needle > strawEnd)
     2357                    l = m + 1;
     2358                else {
     2359                    stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
     2360                    return startCoverageIndex + glyph - strawStart;
     2361                }
     2362            }
     2363        } break;
     2364
     2365        default: {
     2366            // There are no other cases.
     2367            STBTT_assert(0);
     2368        } break;
     2369    }
     2370
     2371    return -1;
    23822372}
    23832373
    23842374static stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
    23852375{
    2386    stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
    2387    switch (classDefFormat)
    2388    {
    2389    case 1: {
    2390       stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
    2391       stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
    2392       stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
    2393 
    2394       if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
    2395          return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
    2396 
    2397       classDefTable = classDef1ValueArray + 2 * glyphCount;
    2398    } break;
    2399 
    2400    case 2: {
    2401       stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
    2402       stbtt_uint8 *classRangeRecords = classDefTable + 4;
    2403 
    2404       // Binary search.
    2405       stbtt_int32 l = 0, r = classRangeCount - 1, m;
    2406       int strawStart, strawEnd, needle = glyph;
    2407       while (l <= r) {
    2408          stbtt_uint8 *classRangeRecord;
    2409          m = (l + r) >> 1;
    2410          classRangeRecord = classRangeRecords + 6 * m;
    2411          strawStart = ttUSHORT(classRangeRecord);
    2412          strawEnd = ttUSHORT(classRangeRecord + 2);
    2413          if (needle < strawStart)
    2414             r = m - 1;
    2415          else if (needle > strawEnd)
    2416             l = m + 1;
    2417          else
    2418             return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
    2419       }
    2420 
    2421       classDefTable = classRangeRecords + 6 * classRangeCount;
    2422    } break;
    2423 
    2424    default: {
    2425       // There are no other cases.
    2426       STBTT_assert(0);
    2427    } break;
    2428    }
    2429 
    2430    return -1;
     2376    stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
     2377    switch(classDefFormat)
     2378    {
     2379        case 1: {
     2380            stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
     2381            stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
     2382            stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
     2383
     2384            if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
     2385                return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
     2386
     2387            // [DEAR IMGUI] Commented to fix static analyzer warning
     2388            //classDefTable = classDef1ValueArray + 2 * glyphCount;
     2389        } break;
     2390
     2391        case 2: {
     2392            stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
     2393            stbtt_uint8 *classRangeRecords = classDefTable + 4;
     2394
     2395            // Binary search.
     2396            stbtt_int32 l=0, r=classRangeCount-1, m;
     2397            int strawStart, strawEnd, needle=glyph;
     2398            while (l <= r) {
     2399                stbtt_uint8 *classRangeRecord;
     2400                m = (l + r) >> 1;
     2401                classRangeRecord = classRangeRecords + 6 * m;
     2402                strawStart = ttUSHORT(classRangeRecord);
     2403                strawEnd = ttUSHORT(classRangeRecord + 2);
     2404                if (needle < strawStart)
     2405                    r = m - 1;
     2406                else if (needle > strawEnd)
     2407                    l = m + 1;
     2408                else
     2409                    return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
     2410            }
     2411
     2412            // [DEAR IMGUI] Commented to fix static analyzer warning
     2413            //classDefTable = classRangeRecords + 6 * classRangeCount;
     2414        } break;
     2415
     2416        default: {
     2417            // There are no other cases.
     2418            STBTT_assert(0);
     2419        } break;
     2420    }
     2421
     2422    return -1;
    24312423}
    24322424
     
    24362428static stbtt_int32  stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
    24372429{
    2438    stbtt_uint16 lookupListOffset;
    2439    stbtt_uint8 *lookupList;
    2440    stbtt_uint16 lookupCount;
    2441    stbtt_uint8 *data;
    2442    stbtt_int32 i;
    2443 
    2444    if (!info->gpos) return 0;
    2445 
    2446    data = info->data + info->gpos;
    2447 
    2448    if (ttUSHORT(data + 0) != 1) return 0; // Major version 1
    2449    if (ttUSHORT(data + 2) != 0) return 0; // Minor version 0
    2450 
    2451    lookupListOffset = ttUSHORT(data + 8);
    2452    lookupList = data + lookupListOffset;
    2453    lookupCount = ttUSHORT(lookupList);
    2454 
    2455    for (i = 0; i<lookupCount; ++i) {
    2456       stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
    2457       stbtt_uint8 *lookupTable = lookupList + lookupOffset;
    2458 
    2459       stbtt_uint16 lookupType = ttUSHORT(lookupTable);
    2460       stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
    2461       stbtt_uint8 *subTableOffsets = lookupTable + 6;
    2462       switch (lookupType) {
    2463       case 2: { // Pair Adjustment Positioning Subtable
    2464          stbtt_int32 sti;
    2465          for (sti = 0; sti<subTableCount; sti++) {
    2466             stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
    2467             stbtt_uint8 *table = lookupTable + subtableOffset;
    2468             stbtt_uint16 posFormat = ttUSHORT(table);
    2469             stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
    2470             stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
    2471             if (coverageIndex == -1) continue;
    2472 
    2473             switch (posFormat) {
    2474             case 1: {
    2475                stbtt_int32 l, r, m;
    2476                int straw, needle;
    2477                stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
    2478                stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
    2479                stbtt_int32 valueRecordPairSizeInBytes = 2;
    2480                stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
    2481                stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
    2482                stbtt_uint8 *pairValueTable = table + pairPosOffset;
    2483                stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
    2484                stbtt_uint8 *pairValueArray = pairValueTable + 2;
    2485                // TODO: Support more formats.
    2486                STBTT_GPOS_TODO_assert(valueFormat1 == 4);
    2487                if (valueFormat1 != 4) return 0;
    2488                STBTT_GPOS_TODO_assert(valueFormat2 == 0);
    2489                if (valueFormat2 != 0) return 0;
    2490 
    2491                STBTT_assert(coverageIndex < pairSetCount);
    2492                STBTT__NOTUSED(pairSetCount);
    2493 
    2494                needle = glyph2;
    2495                r = pairValueCount - 1;
    2496                l = 0;
    2497 
    2498                // Binary search.
    2499                while (l <= r) {
    2500                   stbtt_uint16 secondGlyph;
    2501                   stbtt_uint8 *pairValue;
    2502                   m = (l + r) >> 1;
    2503                   pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
    2504                   secondGlyph = ttUSHORT(pairValue);
    2505                   straw = secondGlyph;
    2506                   if (needle < straw)
    2507                      r = m - 1;
    2508                   else if (needle > straw)
    2509                      l = m + 1;
    2510                   else {
    2511                      stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
    2512                      return xAdvance;
    2513                   }
    2514                }
    2515             } break;
    2516 
    2517             case 2: {
    2518                stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
    2519                stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
    2520 
    2521                stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
    2522                stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
    2523                int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
    2524                int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
    2525 
    2526                stbtt_uint16 class1Count = ttUSHORT(table + 12);
    2527                stbtt_uint16 class2Count = ttUSHORT(table + 14);
    2528                STBTT_assert(glyph1class < class1Count);
    2529                STBTT_assert(glyph2class < class2Count);
    2530 
    2531                // TODO: Support more formats.
    2532                STBTT_GPOS_TODO_assert(valueFormat1 == 4);
    2533                if (valueFormat1 != 4) return 0;
    2534                STBTT_GPOS_TODO_assert(valueFormat2 == 0);
    2535                if (valueFormat2 != 0) return 0;
    2536 
    2537                if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
    2538                   stbtt_uint8 *class1Records = table + 16;
    2539                   stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
    2540                   stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
    2541                   return xAdvance;
    2542                }
    2543             } break;
    2544 
    2545             default: {
    2546                // There are no other cases.
    2547                STBTT_assert(0);
    2548                break;
    2549             };
    2550             }
    2551          }
    2552          break;
    2553       };
    2554 
    2555       default:
    2556          // TODO: Implement other stuff.
    2557          break;
    2558       }
    2559    }
    2560 
    2561    return 0;
     2430    stbtt_uint16 lookupListOffset;
     2431    stbtt_uint8 *lookupList;
     2432    stbtt_uint16 lookupCount;
     2433    stbtt_uint8 *data;
     2434    stbtt_int32 i;
     2435
     2436    if (!info->gpos) return 0;
     2437
     2438    data = info->data + info->gpos;
     2439
     2440    if (ttUSHORT(data+0) != 1) return 0; // Major version 1
     2441    if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
     2442
     2443    lookupListOffset = ttUSHORT(data+8);
     2444    lookupList = data + lookupListOffset;
     2445    lookupCount = ttUSHORT(lookupList);
     2446
     2447    for (i=0; i<lookupCount; ++i) {
     2448        stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
     2449        stbtt_uint8 *lookupTable = lookupList + lookupOffset;
     2450
     2451        stbtt_uint16 lookupType = ttUSHORT(lookupTable);
     2452        stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
     2453        stbtt_uint8 *subTableOffsets = lookupTable + 6;
     2454        switch(lookupType) {
     2455            case 2: { // Pair Adjustment Positioning Subtable
     2456                stbtt_int32 sti;
     2457                for (sti=0; sti<subTableCount; sti++) {
     2458                    stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
     2459                    stbtt_uint8 *table = lookupTable + subtableOffset;
     2460                    stbtt_uint16 posFormat = ttUSHORT(table);
     2461                    stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
     2462                    stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
     2463                    if (coverageIndex == -1) continue;
     2464
     2465                    switch (posFormat) {
     2466                        case 1: {
     2467                            stbtt_int32 l, r, m;
     2468                            int straw, needle;
     2469                            stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
     2470                            stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
     2471                            stbtt_int32 valueRecordPairSizeInBytes = 2;
     2472                            stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
     2473                            stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
     2474                            stbtt_uint8 *pairValueTable = table + pairPosOffset;
     2475                            stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
     2476                            stbtt_uint8 *pairValueArray = pairValueTable + 2;
     2477                            // TODO: Support more formats.
     2478                            STBTT_GPOS_TODO_assert(valueFormat1 == 4);
     2479                            if (valueFormat1 != 4) return 0;
     2480                            STBTT_GPOS_TODO_assert(valueFormat2 == 0);
     2481                            if (valueFormat2 != 0) return 0;
     2482
     2483                            STBTT_assert(coverageIndex < pairSetCount);
     2484                            STBTT__NOTUSED(pairSetCount);
     2485
     2486                            needle=glyph2;
     2487                            r=pairValueCount-1;
     2488                            l=0;
     2489
     2490                            // Binary search.
     2491                            while (l <= r) {
     2492                                stbtt_uint16 secondGlyph;
     2493                                stbtt_uint8 *pairValue;
     2494                                m = (l + r) >> 1;
     2495                                pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
     2496                                secondGlyph = ttUSHORT(pairValue);
     2497                                straw = secondGlyph;
     2498                                if (needle < straw)
     2499                                    r = m - 1;
     2500                                else if (needle > straw)
     2501                                    l = m + 1;
     2502                                else {
     2503                                    stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
     2504                                    return xAdvance;
     2505                                }
     2506                            }
     2507                        } break;
     2508
     2509                        case 2: {
     2510                            stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
     2511                            stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
     2512
     2513                            stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
     2514                            stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
     2515                            int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
     2516                            int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
     2517
     2518                            stbtt_uint16 class1Count = ttUSHORT(table + 12);
     2519                            stbtt_uint16 class2Count = ttUSHORT(table + 14);
     2520                            STBTT_assert(glyph1class < class1Count);
     2521                            STBTT_assert(glyph2class < class2Count);
     2522
     2523                            // TODO: Support more formats.
     2524                            STBTT_GPOS_TODO_assert(valueFormat1 == 4);
     2525                            if (valueFormat1 != 4) return 0;
     2526                            STBTT_GPOS_TODO_assert(valueFormat2 == 0);
     2527                            if (valueFormat2 != 0) return 0;
     2528
     2529                            if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
     2530                                stbtt_uint8 *class1Records = table + 16;
     2531                                stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
     2532                                stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
     2533                                return xAdvance;
     2534                            }
     2535                        } break;
     2536
     2537                        default: {
     2538                            // There are no other cases.
     2539                            STBTT_assert(0);
     2540                            break;
     2541                        } // [DEAR IMGUI] removed ;
     2542                    }
     2543                }
     2544                break;
     2545            } // [DEAR IMGUI] removed ;
     2546
     2547            default:
     2548                // TODO: Implement other stuff.
     2549                break;
     2550        }
     2551    }
     2552
     2553    return 0;
    25622554}
    25632555
     
    25792571   if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs
    25802572      return 0;
    2581    return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info, ch1), stbtt_FindGlyphIndex(info, ch2));
     2573   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));
    25822574}
    25832575
    25842576STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)
    25852577{
    2586    stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info, codepoint), advanceWidth, leftSideBearing);
     2578   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);
    25872579}
    25882580
    25892581STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)
    25902582{
    2591    if (ascent) *ascent = ttSHORT(info->data + info->hhea + 4);
    2592    if (descent) *descent = ttSHORT(info->data + info->hhea + 6);
    2593    if (lineGap) *lineGap = ttSHORT(info->data + info->hhea + 8);
     2583   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);
     2584   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);
     2585   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
    25942586}
    25952587
     
    25992591   if (!tab)
    26002592      return 0;
    2601    if (typoAscent) *typoAscent = ttSHORT(info->data + tab + 68);
    2602    if (typoDescent) *typoDescent = ttSHORT(info->data + tab + 70);
    2603    if (typoLineGap) *typoLineGap = ttSHORT(info->data + tab + 72);
     2593   if (typoAscent ) *typoAscent  = ttSHORT(info->data+tab + 68);
     2594   if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);
     2595   if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);
    26042596   return 1;
    26052597}
     
    26162608{
    26172609   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);
    2618    return (float)height / fheight;
     2610   return (float) height / fheight;
    26192611}
    26202612
     
    26352627//
    26362628
    2637 STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
    2638 {
    2639    int x0 = 0, y0 = 0, x1, y1; // =0 suppresses compiler warning
    2640    if (!stbtt_GetGlyphBox(font, glyph, &x0, &y0, &x1, &y1)) {
     2629STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
     2630{
     2631   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning
     2632   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {
    26412633      // e.g. space character
    26422634      if (ix0) *ix0 = 0;
     
    26442636      if (ix1) *ix1 = 0;
    26452637      if (iy1) *iy1 = 0;
    2646    }
    2647    else {
     2638   } else {
    26482639      // move to integral bboxes (treating pixels as little squares, what pixels get touched)?
    2649       if (ix0) *ix0 = STBTT_ifloor(x0 * scale_x + shift_x);
     2640      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);
    26502641      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);
    2651       if (ix1) *ix1 = STBTT_iceil(x1 * scale_x + shift_x);
    2652       if (iy1) *iy1 = STBTT_iceil(-y0 * scale_y + shift_y);
     2642      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);
     2643      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);
    26532644   }
    26542645}
     
    26562647STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
    26572648{
    2658    stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y, 0.0f, 0.0f, ix0, iy0, ix1, iy1);
     2649   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);
    26592650}
    26602651
    26612652STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)
    26622653{
    2663    stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font, codepoint), scale_x, scale_y, shift_x, shift_y, ix0, iy0, ix1, iy1);
     2654   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);
    26642655}
    26652656
    26662657STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)
    26672658{
    2668    stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y, 0.0f, 0.0f, ix0, iy0, ix1, iy1);
     2659   stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);
    26692660}
    26702661
     
    26892680   if (hh->first_free) {
    26902681      void *p = hh->first_free;
    2691       hh->first_free = *(void **)p;
     2682      hh->first_free = * (void **) p;
    26922683      return p;
    2693    }
    2694    else {
     2684   } else {
    26952685      if (hh->num_remaining_in_head_chunk == 0) {
    26962686         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);
    2697          stbtt__hheap_chunk *c = (stbtt__hheap_chunk *)STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);
     2687         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);
    26982688         if (c == NULL)
    26992689            return NULL;
     
    27032693      }
    27042694      --hh->num_remaining_in_head_chunk;
    2705       return (char *)(hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
     2695      return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;
    27062696   }
    27072697}
     
    27092699static void stbtt__hheap_free(stbtt__hheap *hh, void *p)
    27102700{
    2711    *(void **)p = hh->first_free;
     2701   *(void **) p = hh->first_free;
    27122702   hh->first_free = p;
    27132703}
     
    27242714
    27252715typedef struct stbtt__edge {
    2726    float x0, y0, x1, y1;
     2716   float x0,y0, x1,y1;
    27272717   int invert;
    27282718} stbtt__edge;
     
    27322722{
    27332723   struct stbtt__active_edge *next;
    2734 #if STBTT_RASTERIZER_VERSION==1
    2735    int x, dx;
     2724   #if STBTT_RASTERIZER_VERSION==1
     2725   int x,dx;
    27362726   float ey;
    27372727   int direction;
    2738 #elif STBTT_RASTERIZER_VERSION==2
    2739    float fx, fdx, fdy;
     2728   #elif STBTT_RASTERIZER_VERSION==2
     2729   float fx,fdx,fdy;
    27402730   float direction;
    27412731   float sy;
    27422732   float ey;
    2743 #else
    2744 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
    2745 #endif
     2733   #else
     2734   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
     2735   #endif
    27462736} stbtt__active_edge;
    27472737
     
    27532743static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
    27542744{
    2755    stbtt__active_edge *z = (stbtt__active_edge *)stbtt__hheap_alloc(hh, sizeof(*z), userdata);
     2745   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
    27562746   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
    27572747   STBTT_assert(z != NULL);
    27582748   if (!z) return z;
    2759 
     2749   
    27602750   // round dx down to avoid overshooting
    27612751   if (dxdy < 0)
     
    27752765static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)
    27762766{
    2777    stbtt__active_edge *z = (stbtt__active_edge *)stbtt__hheap_alloc(hh, sizeof(*z), userdata);
     2767   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);
    27782768   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);
    27792769   STBTT_assert(z != NULL);
     
    27812771   if (!z) return z;
    27822772   z->fdx = dxdy;
    2783    z->fdy = dxdy != 0.0f ? (1.0f / dxdy) : 0.0f;
     2773   z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;
    27842774   z->fx = e->x0 + dxdy * (start_point - e->y0);
    27852775   z->fx -= off_x;
     
    28012791{
    28022792   // non-zero winding fill
    2803    int x0 = 0, w = 0;
     2793   int x0=0, w=0;
    28042794
    28052795   while (e) {
     
    28072797         // if we're currently at zero, we need to record the edge start point
    28082798         x0 = e->x; w += e->direction;
    2809       }
    2810       else {
     2799      } else {
    28112800         int x1 = e->x; w += e->direction;
    28122801         // if we went to zero, we need to draw
     
    28182807               if (i == j) {
    28192808                  // x0,x1 are the same pixel, so compute combined coverage
    2820                   scanline[i] = scanline[i] + (stbtt_uint8)((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
    2821                }
    2822                else {
     2809                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);
     2810               } else {
    28232811                  if (i >= 0) // add antialiasing for x0
    2824                      scanline[i] = scanline[i] + (stbtt_uint8)(((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
     2812                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);
    28252813                  else
    28262814                     i = -1; // clip
    28272815
    28282816                  if (j < len) // add antialiasing for x1
    2829                      scanline[j] = scanline[j] + (stbtt_uint8)(((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
     2817                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);
    28302818                  else
    28312819                     j = len; // clip
    28322820
    28332821                  for (++i; i < j; ++i) // fill pixels between x0 and x1
    2834                      scanline[i] = scanline[i] + (stbtt_uint8)max_weight;
     2822                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;
    28352823               }
    28362824            }
    28372825         }
    28382826      }
    2839 
     2827     
    28402828      e = e->next;
    28412829   }
     
    28462834   stbtt__hheap hh = { 0, 0, 0 };
    28472835   stbtt__active_edge *active = NULL;
    2848    int y, j = 0;
     2836   int y,j=0;
    28492837   int max_weight = (255 / vsubsample);  // weight per vertical scanline
    28502838   int s; // vertical subsample index
     
    28522840
    28532841   if (result->w > 512)
    2854       scanline = (unsigned char *)STBTT_malloc(result->w, userdata);
     2842      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);
    28552843   else
    28562844      scanline = scanline_data;
    28572845
    28582846   y = off_y * vsubsample;
    2859    e[n].y0 = (off_y + result->h) * (float)vsubsample + 1;
     2847   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;
    28602848
    28612849   while (j < result->h) {
    28622850      STBTT_memset(scanline, 0, result->w);
    2863       for (s = 0; s < vsubsample; ++s) {
     2851      for (s=0; s < vsubsample; ++s) {
    28642852         // find center of pixel for this scanline
    28652853         float scan_y = y + 0.5f;
     
    28752863               z->direction = 0;
    28762864               stbtt__hheap_free(&hh, z);
    2877             }
    2878             else {
     2865            } else {
    28792866               z->x += z->dx; // advance to position for current scanline
    28802867               step = &((*step)->next); // advance through list
     
    28832870
    28842871         // resort the list if needed
    2885          for (;;) {
    2886             int changed = 0;
     2872         for(;;) {
     2873            int changed=0;
    28872874            step = &active;
    28882875            while (*step && (*step)->next) {
     
    29132900                     z->next = active;
    29142901                     active = z;
    2915                   }
    2916                   else {
     2902                  } else {
    29172903                     // find thing to insert AFTER
    29182904                     stbtt__active_edge *p = active;
     
    29562942   if (y1 < e->sy) return;
    29572943   if (y0 < e->sy) {
    2958       x0 += (x1 - x0) * (e->sy - y0) / (y1 - y0);
     2944      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);
    29592945      y0 = e->sy;
    29602946   }
    29612947   if (y1 > e->ey) {
    2962       x1 += (x1 - x0) * (e->ey - y1) / (y1 - y0);
     2948      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);
    29632949      y1 = e->ey;
    29642950   }
    29652951
    29662952   if (x0 == x)
    2967       STBTT_assert(x1 <= x + 1);
    2968    else if (x0 == x + 1)
     2953      STBTT_assert(x1 <= x+1);
     2954   else if (x0 == x+1)
    29692955      STBTT_assert(x1 >= x);
    29702956   else if (x0 <= x)
    29712957      STBTT_assert(x1 <= x);
    2972    else if (x0 >= x + 1)
    2973       STBTT_assert(x1 >= x + 1);
     2958   else if (x0 >= x+1)
     2959      STBTT_assert(x1 >= x+1);
    29742960   else
    2975       STBTT_assert(x1 >= x && x1 <= x + 1);
     2961      STBTT_assert(x1 >= x && x1 <= x+1);
    29762962
    29772963   if (x0 <= x && x1 <= x)
    2978       scanline[x] += e->direction * (y1 - y0);
    2979    else if (x0 >= x + 1 && x1 >= x + 1)
     2964      scanline[x] += e->direction * (y1-y0);
     2965   else if (x0 >= x+1 && x1 >= x+1)
    29802966      ;
    29812967   else {
    2982       STBTT_assert(x0 >= x && x0 <= x + 1 && x1 >= x && x1 <= x + 1);
    2983       scanline[x] += e->direction * (y1 - y0) * (1 - ((x0 - x) + (x1 - x)) / 2); // coverage = 1 - average x position
     2968      STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);
     2969      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position
    29842970   }
    29852971}
     
    29872973static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
    29882974{
    2989    float y_bottom = y_top + 1;
     2975   float y_bottom = y_top+1;
    29902976
    29912977   while (e) {
     
    29992985         if (x0 < len) {
    30002986            if (x0 >= 0) {
    3001                stbtt__handle_clipped_edge(scanline, (int)x0, e, x0, y_top, x0, y_bottom);
    3002                stbtt__handle_clipped_edge(scanline_fill - 1, (int)x0 + 1, e, x0, y_top, x0, y_bottom);
    3003             }
    3004             else {
    3005                stbtt__handle_clipped_edge(scanline_fill - 1, 0, e, x0, y_top, x0, y_bottom);
     2987               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);
     2988               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);
     2989            } else {
     2990               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);
    30062991            }
    30072992         }
    3008       }
    3009       else {
     2993      } else {
    30102994         float x0 = e->fx;
    30112995         float dx = e->fdx;
    30122996         float xb = x0 + dx;
    30132997         float x_top, x_bottom;
    3014          float sy0, sy1;
     2998         float sy0,sy1;
    30152999         float dy = e->fdy;
    30163000         STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);
     
    30223006            x_top = x0 + dx * (e->sy - y_top);
    30233007            sy0 = e->sy;
    3024          }
    3025          else {
     3008         } else {
    30263009            x_top = x0;
    30273010            sy0 = y_top;
     
    30303013            x_bottom = x0 + dx * (e->ey - y_top);
    30313014            sy1 = e->ey;
    3032          }
    3033          else {
     3015         } else {
    30343016            x_bottom = xb;
    30353017            sy1 = y_bottom;
     
    30393021            // from here on, we don't have to range check x values
    30403022
    3041             if ((int)x_top == (int)x_bottom) {
     3023            if ((int) x_top == (int) x_bottom) {
    30423024               float height;
    30433025               // simple case, only spans one pixel
    3044                int x = (int)x_top;
     3026               int x = (int) x_top;
    30453027               height = sy1 - sy0;
    30463028               STBTT_assert(x >= 0 && x < len);
    3047                scanline[x] += e->direction * (1 - ((x_top - x) + (x_bottom - x)) / 2)  * height;
     3029               scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2)  * height;
    30483030               scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
    3049             }
    3050             else {
    3051                int x, x1, x2;
     3031            } else {
     3032               int x,x1,x2;
    30523033               float y_crossing, step, sign, area;
    30533034               // covers 2+ pixels
     
    30623043                  dy = -dy;
    30633044                  t = x0, x0 = xb, xb = t;
     3045                  // [DEAR IMGUI] Fix static analyzer warning
     3046                  (void)dx; // [ImGui: fix static analyzer warning]
    30643047               }
    30653048
    3066                x1 = (int)x_top;
    3067                x2 = (int)x_bottom;
     3049               x1 = (int) x_top;
     3050               x2 = (int) x_bottom;
    30683051               // compute intersection with y axis at x1+1
    3069                y_crossing = (x1 + 1 - x0) * dy + y_top;
     3052               y_crossing = (x1+1 - x0) * dy + y_top;
    30703053
    30713054               sign = e->direction;
    30723055               // area of the rectangle covered from y0..y_crossing
    3073                area = sign * (y_crossing - sy0);
     3056               area = sign * (y_crossing-sy0);
    30743057               // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
    3075                scanline[x1] += area * (1 - ((x_top - x1) + (x1 + 1 - x1)) / 2);
     3058               scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
    30763059
    30773060               step = sign * dy;
    3078                for (x = x1 + 1; x < x2; ++x) {
    3079                   scanline[x] += area + step / 2;
     3061               for (x = x1+1; x < x2; ++x) {
     3062                  scanline[x] += area + step/2;
    30803063                  area += step;
    30813064               }
    3082                y_crossing += dy * (x2 - (x1 + 1));
     3065               y_crossing += dy * (x2 - (x1+1));
    30833066
    30843067               STBTT_assert(STBTT_fabs(area) <= 1.01f);
    30853068
    3086                scanline[x2] += area + sign * (1 - ((x2 - x2) + (x_bottom - x2)) / 2) * (sy1 - y_crossing);
    3087 
    3088                scanline_fill[x2] += sign * (sy1 - sy0);
     3069               scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
     3070
     3071               scanline_fill[x2] += sign * (sy1-sy0);
    30893072            }
    3090          }
    3091          else {
     3073         } else {
    30923074            // if edge goes outside of box we're drawing, we require
    30933075            // clipping logic. since this does not match the intended use
     
    30953077            // force implementation
    30963078            int x;
    3097             for (x = 0; x < len; ++x) {
     3079            for (x=0; x < len; ++x) {
    30983080               // cases:
    30993081               //
     
    31113093               // rename variables to clearly-defined pairs
    31123094               float y0 = y_top;
    3113                float x1 = (float)(x);
    3114                float x2 = (float)(x + 1);
     3095               float x1 = (float) (x);
     3096               float x2 = (float) (x+1);
    31153097               float x3 = xb;
    31163098               float y3 = y_bottom;
     
    31203102               // y = (x - e->x) / e->dx + y_top
    31213103               float y1 = (x - x0) / dx + y_top;
    3122                float y2 = (x + 1 - x0) / dx + y_top;
     3104               float y2 = (x+1 - x0) / dx + y_top;
    31233105
    31243106               if (x0 < x1 && x3 > x2) {         // three segments descending down-right
    3125                   stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1);
    3126                   stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x2, y2);
    3127                   stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3);
    3128                }
    3129                else if (x3 < x1 && x0 > x2) {  // three segments descending down-left
    3130                   stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2);
    3131                   stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x1, y1);
    3132                   stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3);
    3133                }
    3134                else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right
    3135                   stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1);
    3136                   stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3);
    3137                }
    3138                else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left
    3139                   stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x1, y1);
    3140                   stbtt__handle_clipped_edge(scanline, x, e, x1, y1, x3, y3);
    3141                }
    3142                else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right
    3143                   stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2);
    3144                   stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3);
    3145                }
    3146                else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left
    3147                   stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x2, y2);
    3148                   stbtt__handle_clipped_edge(scanline, x, e, x2, y2, x3, y3);
    3149                }
    3150                else {  // one segment
    3151                   stbtt__handle_clipped_edge(scanline, x, e, x0, y0, x3, y3);
     3107                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
     3108                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);
     3109                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
     3110               } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left
     3111                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
     3112                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);
     3113                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
     3114               } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right
     3115                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
     3116                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
     3117               } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left
     3118                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
     3119                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);
     3120               } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right
     3121                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
     3122                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
     3123               } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left
     3124                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);
     3125                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);
     3126               } else {  // one segment
     3127                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);
    31523128               }
    31533129            }
     
    31633139   stbtt__hheap hh = { 0, 0, 0 };
    31643140   stbtt__active_edge *active = NULL;
    3165    int y, j = 0, i;
     3141   int y,j=0, i;
    31663142   float scanline_data[129], *scanline, *scanline2;
    31673143
     
    31693145
    31703146   if (result->w > 64)
    3171       scanline = (float *)STBTT_malloc((result->w * 2 + 1) * sizeof(float), userdata);
     3147      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);
    31723148   else
    31733149      scanline = scanline_data;
     
    31763152
    31773153   y = off_y;
    3178    e[n].y0 = (float)(off_y + result->h) + 1;
     3154   e[n].y0 = (float) (off_y + result->h) + 1;
    31793155
    31803156   while (j < result->h) {
    31813157      // find center of pixel for this scanline
    3182       float scan_y_top = y + 0.0f;
     3158      float scan_y_top    = y + 0.0f;
    31833159      float scan_y_bottom = y + 1.0f;
    31843160      stbtt__active_edge **step = &active;
    31853161
    3186       STBTT_memset(scanline, 0, result->w * sizeof(scanline[0]));
    3187       STBTT_memset(scanline2, 0, (result->w + 1) * sizeof(scanline[0]));
     3162      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));
     3163      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));
    31883164
    31893165      // update all active edges;
     
    31963172            z->direction = 0;
    31973173            stbtt__hheap_free(&hh, z);
    3198          }
    3199          else {
     3174         } else {
    32003175            step = &((*step)->next); // advance through list
    32013176         }
     
    32073182            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);
    32083183            if (z != NULL) {
    3209                STBTT_assert(z->ey >= scan_y_top);
     3184               if (j == 0 && off_y != 0) {
     3185                  if (z->ey < scan_y_top) {
     3186                     // this can happen due to subpixel positioning and some kind of fp rounding error i think
     3187                     z->ey = scan_y_top;
     3188                  }
     3189               }
     3190               STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds
    32103191               // insert at front
    32113192               z->next = active;
     
    32183199      // now process all active edges
    32193200      if (active)
    3220          stbtt__fill_active_edges_new(scanline, scanline2 + 1, result->w, active, scan_y_top);
     3201         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);
    32213202
    32223203      {
    32233204         float sum = 0;
    3224          for (i = 0; i < result->w; ++i) {
     3205         for (i=0; i < result->w; ++i) {
    32253206            float k;
    32263207            int m;
    32273208            sum += scanline2[i];
    32283209            k = scanline[i] + sum;
    3229             k = (float)STBTT_fabs(k) * 255 + 0.5f;
    3230             m = (int)k;
     3210            k = (float) STBTT_fabs(k)*255 + 0.5f;
     3211            m = (int) k;
    32313212            if (m > 255) m = 255;
    3232             result->pixels[j*result->stride + i] = (unsigned char)m;
     3213            result->pixels[j*result->stride + i] = (unsigned char) m;
    32333214         }
    32343215      }
     
    32583239static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)
    32593240{
    3260    int i, j;
    3261    for (i = 1; i < n; ++i) {
     3241   int i,j;
     3242   for (i=1; i < n; ++i) {
    32623243      stbtt__edge t = p[i], *a = &t;
    32633244      j = i;
    32643245      while (j > 0) {
    3265          stbtt__edge *b = &p[j - 1];
    3266          int c = STBTT__COMPARE(a, b);
     3246         stbtt__edge *b = &p[j-1];
     3247         int c = STBTT__COMPARE(a,b);
    32673248         if (!c) break;
    3268          p[j] = p[j - 1];
     3249         p[j] = p[j-1];
    32693250         --j;
    32703251      }
     
    32763257static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)
    32773258{
    3278    /* threshhold for transitioning to insertion sort */
     3259   /* threshold for transitioning to insertion sort */
    32793260   while (n > 12) {
    32803261      stbtt__edge t;
    3281       int c01, c12, c, m, i, j;
     3262      int c01,c12,c,m,i,j;
    32823263
    32833264      /* compute median of three */
    32843265      m = n >> 1;
    3285       c01 = STBTT__COMPARE(&p[0], &p[m]);
    3286       c12 = STBTT__COMPARE(&p[m], &p[n - 1]);
     3266      c01 = STBTT__COMPARE(&p[0],&p[m]);
     3267      c12 = STBTT__COMPARE(&p[m],&p[n-1]);
    32873268      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */
    32883269      if (c01 != c12) {
    32893270         /* otherwise, we'll need to swap something else to middle */
    32903271         int z;
    3291          c = STBTT__COMPARE(&p[0], &p[n - 1]);
     3272         c = STBTT__COMPARE(&p[0],&p[n-1]);
    32923273         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */
    32933274         /* 0<mid && mid>n:  0>n => 0; 0<n => n */
    3294          z = (c == c12) ? 0 : n - 1;
     3275         z = (c == c12) ? 0 : n-1;
    32953276         t = p[z];
    32963277         p[z] = p[m];
     
    33043285
    33053286      /* partition loop */
    3306       i = 1;
    3307       j = n - 1;
    3308       for (;;) {
     3287      i=1;
     3288      j=n-1;
     3289      for(;;) {
    33093290         /* handling of equality is crucial here */
    33103291         /* for sentinels & efficiency with duplicates */
    3311          for (;; ++i) {
     3292         for (;;++i) {
    33123293            if (!STBTT__COMPARE(&p[i], &p[0])) break;
    33133294         }
    3314          for (;; --j) {
     3295         for (;;--j) {
    33153296            if (!STBTT__COMPARE(&p[0], &p[j])) break;
    33163297         }
     
    33253306      }
    33263307      /* recurse on smaller side, iterate on larger */
    3327       if (j < (n - i)) {
    3328          stbtt__sort_edges_quicksort(p, j);
    3329          p = p + i;
    3330          n = n - i;
    3331       }
    3332       else {
    3333          stbtt__sort_edges_quicksort(p + i, n - i);
     3308      if (j < (n-i)) {
     3309         stbtt__sort_edges_quicksort(p,j);
     3310         p = p+i;
     3311         n = n-i;
     3312      } else {
     3313         stbtt__sort_edges_quicksort(p+i, n-i);
    33343314         n = j;
    33353315      }
     
    33453325typedef struct
    33463326{
    3347    float x, y;
     3327   float x,y;
    33483328} stbtt__point;
    33493329
     
    33523332   float y_scale_inv = invert ? -scale_y : scale_y;
    33533333   stbtt__edge *e;
    3354    int n, i, j, k, m;
     3334   int n,i,j,k,m;
    33553335#if STBTT_RASTERIZER_VERSION == 1
    33563336   int vsubsample = result->h < 8 ? 15 : 5;
     
    33583338   int vsubsample = 1;
    33593339#else
    3360 #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
     3340   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"
    33613341#endif
    33623342   // vsubsample should divide 255 evenly; otherwise we won't reach full opacity
     
    33643344   // now we have to blow out the windings into explicit edge lists
    33653345   n = 0;
    3366    for (i = 0; i < windings; ++i)
     3346   for (i=0; i < windings; ++i)
    33673347      n += wcount[i];
    33683348
    3369    e = (stbtt__edge *)STBTT_malloc(sizeof(*e) * (n + 1), userdata); // add an extra one as a sentinel
     3349   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel
    33703350   if (e == 0) return;
    33713351   n = 0;
    33723352
    3373    m = 0;
    3374    for (i = 0; i < windings; ++i) {
     3353   m=0;
     3354   for (i=0; i < windings; ++i) {
    33753355      stbtt__point *p = pts + m;
    33763356      m += wcount[i];
    3377       j = wcount[i] - 1;
    3378       for (k = 0; k < wcount[i]; j = k++) {
    3379          int a = k, b = j;
     3357      j = wcount[i]-1;
     3358      for (k=0; k < wcount[i]; j=k++) {
     3359         int a=k,b=j;
    33803360         // skip the edge if horizontal
    33813361         if (p[j].y == p[k].y)
     
    33853365         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {
    33863366            e[n].invert = 1;
    3387             a = j, b = k;
     3367            a=j,b=k;
    33883368         }
    33893369         e[n].x0 = p[a].x * scale_x + shift_x;
     
    34123392}
    34133393
    3414 // tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching
     3394// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching
    34153395static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)
    34163396{
    34173397   // midpoint
    3418    float mx = (x0 + 2 * x1 + x2) / 4;
    3419    float my = (y0 + 2 * y1 + y2) / 4;
     3398   float mx = (x0 + 2*x1 + x2)/4;
     3399   float my = (y0 + 2*y1 + y2)/4;
    34203400   // versus directly drawn line
    3421    float dx = (x0 + x2) / 2 - mx;
    3422    float dy = (y0 + y2) / 2 - my;
     3401   float dx = (x0+x2)/2 - mx;
     3402   float dy = (y0+y2)/2 - my;
    34233403   if (n > 16) // 65536 segments on one curve better be enough!
    34243404      return 1;
    3425    if (dx*dx + dy * dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
    3426       stbtt__tesselate_curve(points, num_points, x0, y0, (x0 + x1) / 2.0f, (y0 + y1) / 2.0f, mx, my, objspace_flatness_squared, n + 1);
    3427       stbtt__tesselate_curve(points, num_points, mx, my, (x1 + x2) / 2.0f, (y1 + y2) / 2.0f, x2, y2, objspace_flatness_squared, n + 1);
    3428    }
    3429    else {
    3430       stbtt__add_point(points, *num_points, x2, y2);
    3431       *num_points = *num_points + 1;
     3405   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA
     3406      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);
     3407      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);
     3408   } else {
     3409      stbtt__add_point(points, *num_points,x2,y2);
     3410      *num_points = *num_points+1;
    34323411   }
    34333412   return 1;
     
    34373416{
    34383417   // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
    3439    float dx0 = x1 - x0;
    3440    float dy0 = y1 - y0;
    3441    float dx1 = x2 - x1;
    3442    float dy1 = y2 - y1;
    3443    float dx2 = x3 - x2;
    3444    float dy2 = y3 - y2;
    3445    float dx = x3 - x0;
    3446    float dy = y3 - y0;
    3447    float longlen = (float)(STBTT_sqrt(dx0*dx0 + dy0 * dy0) + STBTT_sqrt(dx1*dx1 + dy1 * dy1) + STBTT_sqrt(dx2*dx2 + dy2 * dy2));
    3448    float shortlen = (float)STBTT_sqrt(dx*dx + dy * dy);
    3449    float flatness_squared = longlen * longlen - shortlen * shortlen;
     3418   float dx0 = x1-x0;
     3419   float dy0 = y1-y0;
     3420   float dx1 = x2-x1;
     3421   float dy1 = y2-y1;
     3422   float dx2 = x3-x2;
     3423   float dy2 = y3-y2;
     3424   float dx = x3-x0;
     3425   float dy = y3-y0;
     3426   float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
     3427   float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);
     3428   float flatness_squared = longlen*longlen-shortlen*shortlen;
    34503429
    34513430   if (n > 16) // 65536 segments on one curve better be enough!
     
    34533432
    34543433   if (flatness_squared > objspace_flatness_squared) {
    3455       float x01 = (x0 + x1) / 2;
    3456       float y01 = (y0 + y1) / 2;
    3457       float x12 = (x1 + x2) / 2;
    3458       float y12 = (y1 + y2) / 2;
    3459       float x23 = (x2 + x3) / 2;
    3460       float y23 = (y2 + y3) / 2;
    3461 
    3462       float xa = (x01 + x12) / 2;
    3463       float ya = (y01 + y12) / 2;
    3464       float xb = (x12 + x23) / 2;
    3465       float yb = (y12 + y23) / 2;
    3466 
    3467       float mx = (xa + xb) / 2;
    3468       float my = (ya + yb) / 2;
    3469 
    3470       stbtt__tesselate_cubic(points, num_points, x0, y0, x01, y01, xa, ya, mx, my, objspace_flatness_squared, n + 1);
    3471       stbtt__tesselate_cubic(points, num_points, mx, my, xb, yb, x23, y23, x3, y3, objspace_flatness_squared, n + 1);
    3472    }
    3473    else {
    3474       stbtt__add_point(points, *num_points, x3, y3);
    3475       *num_points = *num_points + 1;
     3434      float x01 = (x0+x1)/2;
     3435      float y01 = (y0+y1)/2;
     3436      float x12 = (x1+x2)/2;
     3437      float y12 = (y1+y2)/2;
     3438      float x23 = (x2+x3)/2;
     3439      float y23 = (y2+y3)/2;
     3440
     3441      float xa = (x01+x12)/2;
     3442      float ya = (y01+y12)/2;
     3443      float xb = (x12+x23)/2;
     3444      float yb = (y12+y23)/2;
     3445
     3446      float mx = (xa+xb)/2;
     3447      float my = (ya+yb)/2;
     3448
     3449      stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
     3450      stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
     3451   } else {
     3452      stbtt__add_point(points, *num_points,x3,y3);
     3453      *num_points = *num_points+1;
    34763454   }
    34773455}
     
    34803458static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
    34813459{
    3482    stbtt__point *points = 0;
    3483    int num_points = 0;
     3460   stbtt__point *points=0;
     3461   int num_points=0;
    34843462
    34853463   float objspace_flatness_squared = objspace_flatness * objspace_flatness;
    3486    int i, n = 0, start = 0, pass;
     3464   int i,n=0,start=0, pass;
    34873465
    34883466   // count how many "moves" there are to get the contour count
    3489    for (i = 0; i < num_verts; ++i)
     3467   for (i=0; i < num_verts; ++i)
    34903468      if (vertices[i].type == STBTT_vmove)
    34913469         ++n;
     
    34943472   if (n == 0) return 0;
    34953473
    3496    *contour_lengths = (int *)STBTT_malloc(sizeof(**contour_lengths) * n, userdata);
     3474   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);
    34973475
    34983476   if (*contour_lengths == 0) {
     
    35023480
    35033481   // make two passes through the points so we don't need to realloc
    3504    for (pass = 0; pass < 2; ++pass) {
    3505       float x = 0, y = 0;
     3482   for (pass=0; pass < 2; ++pass) {
     3483      float x=0,y=0;
    35063484      if (pass == 1) {
    3507          points = (stbtt__point *)STBTT_malloc(num_points * sizeof(points[0]), userdata);
     3485         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);
    35083486         if (points == NULL) goto error;
    35093487      }
    35103488      num_points = 0;
    3511       n = -1;
    3512       for (i = 0; i < num_verts; ++i) {
     3489      n= -1;
     3490      for (i=0; i < num_verts; ++i) {
    35133491         switch (vertices[i].type) {
    3514          case STBTT_vmove:
    3515             // start the next contour
    3516             if (n >= 0)
    3517                (*contour_lengths)[n] = num_points - start;
    3518             ++n;
    3519             start = num_points;
    3520 
    3521             x = vertices[i].x, y = vertices[i].y;
    3522             stbtt__add_point(points, num_points++, x, y);
    3523             break;
    3524          case STBTT_vline:
    3525             x = vertices[i].x, y = vertices[i].y;
    3526             stbtt__add_point(points, num_points++, x, y);
    3527             break;
    3528          case STBTT_vcurve:
    3529             stbtt__tesselate_curve(points, &num_points, x, y,
    3530                vertices[i].cx, vertices[i].cy,
    3531                vertices[i].x, vertices[i].y,
    3532                objspace_flatness_squared, 0);
    3533             x = vertices[i].x, y = vertices[i].y;
    3534             break;
    3535          case STBTT_vcubic:
    3536             stbtt__tesselate_cubic(points, &num_points, x, y,
    3537                vertices[i].cx, vertices[i].cy,
    3538                vertices[i].cx1, vertices[i].cy1,
    3539                vertices[i].x, vertices[i].y,
    3540                objspace_flatness_squared, 0);
    3541             x = vertices[i].x, y = vertices[i].y;
    3542             break;
     3492            case STBTT_vmove:
     3493               // start the next contour
     3494               if (n >= 0)
     3495                  (*contour_lengths)[n] = num_points - start;
     3496               ++n;
     3497               start = num_points;
     3498
     3499               x = vertices[i].x, y = vertices[i].y;
     3500               stbtt__add_point(points, num_points++, x,y);
     3501               break;
     3502            case STBTT_vline:
     3503               x = vertices[i].x, y = vertices[i].y;
     3504               stbtt__add_point(points, num_points++, x, y);
     3505               break;
     3506            case STBTT_vcurve:
     3507               stbtt__tesselate_curve(points, &num_points, x,y,
     3508                                        vertices[i].cx, vertices[i].cy,
     3509                                        vertices[i].x, vertices[i].y,
     3510                                        objspace_flatness_squared, 0);
     3511               x = vertices[i].x, y = vertices[i].y;
     3512               break;
     3513            case STBTT_vcubic:
     3514               stbtt__tesselate_cubic(points, &num_points, x,y,
     3515                                        vertices[i].cx, vertices[i].cy,
     3516                                        vertices[i].cx1, vertices[i].cy1,
     3517                                        vertices[i].x, vertices[i].y,
     3518                                        objspace_flatness_squared, 0);
     3519               x = vertices[i].x, y = vertices[i].y;
     3520               break;
    35433521         }
    35443522      }
     
    35573535STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
    35583536{
    3559    float scale = scale_x > scale_y ? scale_y : scale_x;
    3560    int winding_count = 0;
    3561    int *winding_lengths = NULL;
     3537   float scale            = scale_x > scale_y ? scale_y : scale_x;
     3538   int winding_count      = 0;
     3539   int *winding_lengths   = NULL;
    35623540   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
    35633541   if (windings) {
     
    35753553STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)
    35763554{
    3577    int ix0, iy0, ix1, iy1;
     3555   int ix0,iy0,ix1,iy1;
    35783556   stbtt__bitmap gbm;
    3579    stbtt_vertex *vertices;
     3557   stbtt_vertex *vertices;   
    35803558   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
    35813559
     
    35893567   }
    35903568
    3591    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0, &iy0, &ix1, &iy1);
     3569   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);
    35923570
    35933571   // now we get the size
     
    35963574   gbm.pixels = NULL; // in case we error
    35973575
    3598    if (width) *width = gbm.w;
     3576   if (width ) *width = gbm.w;
    35993577   if (height) *height = gbm.h;
    3600    if (xoff) *xoff = ix0;
    3601    if (yoff) *yoff = iy0;
    3602 
     3578   if (xoff  ) *xoff  = ix0;
     3579   if (yoff  ) *yoff  = iy0;
     3580   
    36033581   if (gbm.w && gbm.h) {
    3604       gbm.pixels = (unsigned char *)STBTT_malloc(gbm.w * gbm.h, info->userdata);
     3582      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);
    36053583      if (gbm.pixels) {
    36063584         gbm.stride = gbm.w;
     
    36113589   STBTT_free(vertices, info->userdata);
    36123590   return gbm.pixels;
    3613 }
     3591}   
    36143592
    36153593STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)
     
    36203598STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)
    36213599{
    3622    int ix0, iy0;
     3600   int ix0,iy0;
    36233601   stbtt_vertex *vertices;
    36243602   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);
    3625    stbtt__bitmap gbm;
    3626 
    3627    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0, &iy0, 0, 0);
     3603   stbtt__bitmap gbm;   
     3604
     3605   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);
    36283606   gbm.pixels = output;
    36293607   gbm.w = out_w;
     
    36323610
    36333611   if (gbm.w && gbm.h)
    3634       stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);
     3612      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);
    36353613
    36363614   STBTT_free(vertices, info->userdata);
     
    36393617STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)
    36403618{
    3641    stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f, 0.0f, glyph);
     3619   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);
    36423620}
    36433621
    36443622STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
    36453623{
    3646    return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info, codepoint), width, height, xoff, yoff);
    3647 }
     3624   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);
     3625}   
    36483626
    36493627STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)
    36503628{
    3651    stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info, codepoint));
     3629   stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));
    36523630}
    36533631
    36543632STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)
    36553633{
    3656    stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info, codepoint));
     3634   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));
    36573635}
    36583636
    36593637STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)
    36603638{
    3661    return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, codepoint, width, height, xoff, yoff);
    3662 }
     3639   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);
     3640}   
    36633641
    36643642STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)
    36653643{
    3666    stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f, 0.0f, codepoint);
     3644   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);
    36673645}
    36683646
     
    36743652
    36753653static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)
    3676    float pixel_height,                     // height of font in pixels
    3677    unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
    3678    int first_char, int num_chars,          // characters to bake
    3679    stbtt_bakedchar *chardata)
     3654                                float pixel_height,                     // height of font in pixels
     3655                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in
     3656                                int first_char, int num_chars,          // characters to bake
     3657                                stbtt_bakedchar *chardata)
    36803658{
    36813659   float scale;
    3682    int x, y, bottom_y, i;
     3660   int x,y,bottom_y, i;
    36833661   stbtt_fontinfo f;
    36843662   f.userdata = NULL;
     
    36863664      return -1;
    36873665   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels
    3688    x = y = 1;
     3666   x=y=1;
    36893667   bottom_y = 1;
    36903668
    36913669   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);
    36923670
    3693    for (i = 0; i < num_chars; ++i) {
    3694       int advance, lsb, x0, y0, x1, y1, gw, gh;
     3671   for (i=0; i < num_chars; ++i) {
     3672      int advance, lsb, x0,y0,x1,y1,gw,gh;
    36953673      int g = stbtt_FindGlyphIndex(&f, first_char + i);
    36963674      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);
    3697       stbtt_GetGlyphBitmapBox(&f, g, scale, scale, &x0, &y0, &x1, &y1);
    3698       gw = x1 - x0;
    3699       gh = y1 - y0;
     3675      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);
     3676      gw = x1-x0;
     3677      gh = y1-y0;
    37003678      if (x + gw + 1 >= pw)
    37013679         y = bottom_y, x = 1; // advance to next row
    37023680      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row
    37033681         return -i;
    3704       STBTT_assert(x + gw < pw);
    3705       STBTT_assert(y + gh < ph);
    3706       stbtt_MakeGlyphBitmap(&f, pixels + x + y * pw, gw, gh, pw, scale, scale, g);
    3707       chardata[i].x0 = (stbtt_int16)x;
    3708       chardata[i].y0 = (stbtt_int16)y;
    3709       chardata[i].x1 = (stbtt_int16)(x + gw);
    3710       chardata[i].y1 = (stbtt_int16)(y + gh);
     3682      STBTT_assert(x+gw < pw);
     3683      STBTT_assert(y+gh < ph);
     3684      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);
     3685      chardata[i].x0 = (stbtt_int16) x;
     3686      chardata[i].y0 = (stbtt_int16) y;
     3687      chardata[i].x1 = (stbtt_int16) (x + gw);
     3688      chardata[i].y1 = (stbtt_int16) (y + gh);
    37113689      chardata[i].xadvance = scale * advance;
    3712       chardata[i].xoff = (float)x0;
    3713       chardata[i].yoff = (float)y0;
     3690      chardata[i].xoff     = (float) x0;
     3691      chardata[i].yoff     = (float) y0;
    37143692      x = x + gw + 1;
    3715       if (y + gh + 1 > bottom_y)
    3716          bottom_y = y + gh + 1;
     3693      if (y+gh+1 > bottom_y)
     3694         bottom_y = y+gh+1;
    37173695   }
    37183696   return bottom_y;
     
    37623740typedef struct
    37633741{
    3764    int width, height;
    3765    int x, y, bottom_y;
     3742   int width,height;
     3743   int x,y,bottom_y;
    37663744} stbrp_context;
    37673745
     
    37733751struct stbrp_rect
    37743752{
    3775    stbrp_coord x, y;
    3776    int id, w, h, was_packed;
     3753   stbrp_coord x,y;
     3754   int id,w,h,was_packed;
    37773755};
    37783756
    37793757static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)
    37803758{
    3781    con->width = pw;
     3759   con->width  = pw;
    37823760   con->height = ph;
    37833761   con->x = 0;
     
    37853763   con->bottom_y = 0;
    37863764   STBTT__NOTUSED(nodes);
    3787    STBTT__NOTUSED(num_nodes);
     3765   STBTT__NOTUSED(num_nodes);   
    37883766}
    37893767
     
    37913769{
    37923770   int i;
    3793    for (i = 0; i < num_rects; ++i) {
     3771   for (i=0; i < num_rects; ++i) {
    37943772      if (con->x + rects[i].w > con->width) {
    37953773         con->x = 0;
     
    38053783         con->bottom_y = con->y + rects[i].h;
    38063784   }
    3807    for (; i < num_rects; ++i)
     3785   for (   ; i < num_rects; ++i)
    38083786      rects[i].was_packed = 0;
    38093787}
     
    38193797STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)
    38203798{
    3821    stbrp_context *context = (stbrp_context *)STBTT_malloc(sizeof(*context), alloc_context);
     3799   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);
    38223800   int            num_nodes = pw - padding;
    3823    stbrp_node    *nodes = (stbrp_node    *)STBTT_malloc(sizeof(*nodes) * num_nodes, alloc_context);
     3801   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);
    38243802
    38253803   if (context == NULL || nodes == NULL) {
    38263804      if (context != NULL) STBTT_free(context, alloc_context);
    3827       if (nodes != NULL) STBTT_free(nodes, alloc_context);
     3805      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);
    38283806      return 0;
    38293807   }
     
    38393817   spc->h_oversample = 1;
    38403818   spc->v_oversample = 1;
    3841 
    3842    stbrp_init_target(context, pw - padding, ph - padding, nodes, num_nodes);
     3819   spc->skip_missing = 0;
     3820
     3821   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);
    38433822
    38443823   if (pixels)
     
    38483827}
    38493828
    3850 STBTT_DEF void stbtt_PackEnd(stbtt_pack_context *spc)
    3851 {
    3852    STBTT_free(spc->nodes, spc->user_allocator_context);
     3829STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)
     3830{
     3831   STBTT_free(spc->nodes    , spc->user_allocator_context);
    38533832   STBTT_free(spc->pack_info, spc->user_allocator_context);
    38543833}
     
    38643843}
    38653844
     3845STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)
     3846{
     3847   spc->skip_missing = skip;
     3848}
     3849
    38663850#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)
    38673851
     
    38723856   int j;
    38733857   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
    3874    for (j = 0; j < h; ++j) {
     3858   for (j=0; j < h; ++j) {
    38753859      int i;
    38763860      unsigned int total;
     
    38813865      // make kernel_width a constant in common cases so compiler can optimize out the divide
    38823866      switch (kernel_width) {
    3883       case 2:
    3884          for (i = 0; i <= safe_w; ++i) {
    3885             total += pixels[i] - buffer[i & STBTT__OVER_MASK];
    3886             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i];
    3887             pixels[i] = (unsigned char)(total / 2);
    3888          }
    3889          break;
    3890       case 3:
    3891          for (i = 0; i <= safe_w; ++i) {
    3892             total += pixels[i] - buffer[i & STBTT__OVER_MASK];
    3893             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i];
    3894             pixels[i] = (unsigned char)(total / 3);
    3895          }
    3896          break;
    3897       case 4:
    3898          for (i = 0; i <= safe_w; ++i) {
    3899             total += pixels[i] - buffer[i & STBTT__OVER_MASK];
    3900             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i];
    3901             pixels[i] = (unsigned char)(total / 4);
    3902          }
    3903          break;
    3904       case 5:
    3905          for (i = 0; i <= safe_w; ++i) {
    3906             total += pixels[i] - buffer[i & STBTT__OVER_MASK];
    3907             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i];
    3908             pixels[i] = (unsigned char)(total / 5);
    3909          }
    3910          break;
    3911       default:
    3912          for (i = 0; i <= safe_w; ++i) {
    3913             total += pixels[i] - buffer[i & STBTT__OVER_MASK];
    3914             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i];
    3915             pixels[i] = (unsigned char)(total / kernel_width);
    3916          }
    3917          break;
     3867         case 2:
     3868            for (i=0; i <= safe_w; ++i) {
     3869               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
     3870               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
     3871               pixels[i] = (unsigned char) (total / 2);
     3872            }
     3873            break;
     3874         case 3:
     3875            for (i=0; i <= safe_w; ++i) {
     3876               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
     3877               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
     3878               pixels[i] = (unsigned char) (total / 3);
     3879            }
     3880            break;
     3881         case 4:
     3882            for (i=0; i <= safe_w; ++i) {
     3883               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
     3884               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
     3885               pixels[i] = (unsigned char) (total / 4);
     3886            }
     3887            break;
     3888         case 5:
     3889            for (i=0; i <= safe_w; ++i) {
     3890               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
     3891               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
     3892               pixels[i] = (unsigned char) (total / 5);
     3893            }
     3894            break;
     3895         default:
     3896            for (i=0; i <= safe_w; ++i) {
     3897               total += pixels[i] - buffer[i & STBTT__OVER_MASK];
     3898               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];
     3899               pixels[i] = (unsigned char) (total / kernel_width);
     3900            }
     3901            break;
    39183902      }
    39193903
     
    39213905         STBTT_assert(pixels[i] == 0);
    39223906         total -= buffer[i & STBTT__OVER_MASK];
    3923          pixels[i] = (unsigned char)(total / kernel_width);
     3907         pixels[i] = (unsigned char) (total / kernel_width);
    39243908      }
    39253909
     
    39343918   int j;
    39353919   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze
    3936    for (j = 0; j < w; ++j) {
     3920   for (j=0; j < w; ++j) {
    39373921      int i;
    39383922      unsigned int total;
     
    39433927      // make kernel_width a constant in common cases so compiler can optimize out the divide
    39443928      switch (kernel_width) {
    3945       case 2:
    3946          for (i = 0; i <= safe_h; ++i) {
    3947             total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
    3948             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
    3949             pixels[i*stride_in_bytes] = (unsigned char)(total / 2);
    3950          }
    3951          break;
    3952       case 3:
    3953          for (i = 0; i <= safe_h; ++i) {
    3954             total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
    3955             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
    3956             pixels[i*stride_in_bytes] = (unsigned char)(total / 3);
    3957          }
    3958          break;
    3959       case 4:
    3960          for (i = 0; i <= safe_h; ++i) {
    3961             total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
    3962             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
    3963             pixels[i*stride_in_bytes] = (unsigned char)(total / 4);
    3964          }
    3965          break;
    3966       case 5:
    3967          for (i = 0; i <= safe_h; ++i) {
    3968             total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
    3969             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
    3970             pixels[i*stride_in_bytes] = (unsigned char)(total / 5);
    3971          }
    3972          break;
    3973       default:
    3974          for (i = 0; i <= safe_h; ++i) {
    3975             total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
    3976             buffer[(i + kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
    3977             pixels[i*stride_in_bytes] = (unsigned char)(total / kernel_width);
    3978          }
    3979          break;
     3929         case 2:
     3930            for (i=0; i <= safe_h; ++i) {
     3931               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
     3932               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
     3933               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);
     3934            }
     3935            break;
     3936         case 3:
     3937            for (i=0; i <= safe_h; ++i) {
     3938               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
     3939               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
     3940               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);
     3941            }
     3942            break;
     3943         case 4:
     3944            for (i=0; i <= safe_h; ++i) {
     3945               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
     3946               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
     3947               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);
     3948            }
     3949            break;
     3950         case 5:
     3951            for (i=0; i <= safe_h; ++i) {
     3952               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
     3953               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
     3954               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);
     3955            }
     3956            break;
     3957         default:
     3958            for (i=0; i <= safe_h; ++i) {
     3959               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];
     3960               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];
     3961               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
     3962            }
     3963            break;
    39803964      }
    39813965
     
    39833967         STBTT_assert(pixels[i*stride_in_bytes] == 0);
    39843968         total -= buffer[i & STBTT__OVER_MASK];
    3985          pixels[i*stride_in_bytes] = (unsigned char)(total / kernel_width);
     3969         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);
    39863970      }
    39873971
     
    40053989STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
    40063990{
    4007    int i, j, k;
    4008 
    4009    k = 0;
    4010    for (i = 0; i < num_ranges; ++i) {
     3991   int i,j,k;
     3992
     3993   k=0;
     3994   for (i=0; i < num_ranges; ++i) {
    40113995      float fh = ranges[i].font_size;
    40123996      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
    4013       ranges[i].h_oversample = (unsigned char)spc->h_oversample;
    4014       ranges[i].v_oversample = (unsigned char)spc->v_oversample;
    4015       for (j = 0; j < ranges[i].num_chars; ++j) {
    4016          int x0, y0, x1, y1;
     3997      ranges[i].h_oversample = (unsigned char) spc->h_oversample;
     3998      ranges[i].v_oversample = (unsigned char) spc->v_oversample;
     3999      for (j=0; j < ranges[i].num_chars; ++j) {
     4000         int x0,y0,x1,y1;
    40174001         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
    40184002         int glyph = stbtt_FindGlyphIndex(info, codepoint);
    4019          stbtt_GetGlyphBitmapBoxSubpixel(info, glyph,
    4020             scale * spc->h_oversample,
    4021             scale * spc->v_oversample,
    4022             0, 0,
    4023             &x0, &y0, &x1, &y1);
    4024          rects[k].w = (stbrp_coord)(x1 - x0 + spc->padding + spc->h_oversample - 1);
    4025          rects[k].h = (stbrp_coord)(y1 - y0 + spc->padding + spc->v_oversample - 1);
     4003         if (glyph == 0 && spc->skip_missing) {
     4004            rects[k].w = rects[k].h = 0;
     4005         } else {
     4006            stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,
     4007                                            scale * spc->h_oversample,
     4008                                            scale * spc->v_oversample,
     4009                                            0,0,
     4010                                            &x0,&y0,&x1,&y1);
     4011            rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);
     4012            rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);
     4013         }
    40264014         ++k;
    40274015      }
     
    40344022{
    40354023   stbtt_MakeGlyphBitmapSubpixel(info,
    4036       output,
    4037       out_w - (prefilter_x - 1),
    4038       out_h - (prefilter_y - 1),
    4039       out_stride,
    4040       scale_x,
    4041       scale_y,
    4042       shift_x,
    4043       shift_y,
    4044       glyph);
     4024                                 output,
     4025                                 out_w - (prefilter_x - 1),
     4026                                 out_h - (prefilter_y - 1),
     4027                                 out_stride,
     4028                                 scale_x,
     4029                                 scale_y,
     4030                                 shift_x,
     4031                                 shift_y,
     4032                                 glyph);
    40454033
    40464034   if (prefilter_x > 1)
     
    40574045STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
    40584046{
    4059    int i, j, k, return_value = 1;
     4047   int i,j,k, return_value = 1;
    40604048
    40614049   // save current values
     
    40644052
    40654053   k = 0;
    4066    for (i = 0; i < num_ranges; ++i) {
     4054   for (i=0; i < num_ranges; ++i) {
    40674055      float fh = ranges[i].font_size;
    40684056      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);
    4069       float recip_h, recip_v, sub_x, sub_y;
     4057      float recip_h,recip_v,sub_x,sub_y;
    40704058      spc->h_oversample = ranges[i].h_oversample;
    40714059      spc->v_oversample = ranges[i].v_oversample;
     
    40744062      sub_x = stbtt__oversample_shift(spc->h_oversample);
    40754063      sub_y = stbtt__oversample_shift(spc->v_oversample);
    4076       for (j = 0; j < ranges[i].num_chars; ++j) {
     4064      for (j=0; j < ranges[i].num_chars; ++j) {
    40774065         stbrp_rect *r = &rects[k];
    4078          if (r->was_packed) {
     4066         if (r->was_packed && r->w != 0 && r->h != 0) {
    40794067            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];
    4080             int advance, lsb, x0, y0, x1, y1;
     4068            int advance, lsb, x0,y0,x1,y1;
    40814069            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];
    40824070            int glyph = stbtt_FindGlyphIndex(info, codepoint);
    4083             stbrp_coord pad = (stbrp_coord)spc->padding;
     4071            stbrp_coord pad = (stbrp_coord) spc->padding;
    40844072
    40854073            // pad on left and top
     
    40904078            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);
    40914079            stbtt_GetGlyphBitmapBox(info, glyph,
    4092                scale * spc->h_oversample,
    4093                scale * spc->v_oversample,
    4094                &x0, &y0, &x1, &y1);
     4080                                    scale * spc->h_oversample,
     4081                                    scale * spc->v_oversample,
     4082                                    &x0,&y0,&x1,&y1);
    40954083            stbtt_MakeGlyphBitmapSubpixel(info,
    4096                spc->pixels + r->x + r->y*spc->stride_in_bytes,
    4097                r->w - spc->h_oversample + 1,
    4098                r->h - spc->v_oversample + 1,
    4099                spc->stride_in_bytes,
    4100                scale * spc->h_oversample,
    4101                scale * spc->v_oversample,
    4102                0, 0,
    4103                glyph);
     4084                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,
     4085                                          r->w - spc->h_oversample+1,
     4086                                          r->h - spc->v_oversample+1,
     4087                                          spc->stride_in_bytes,
     4088                                          scale * spc->h_oversample,
     4089                                          scale * spc->v_oversample,
     4090                                          0,0,
     4091                                          glyph);
    41044092
    41054093            if (spc->h_oversample > 1)
    41064094               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
    4107                   r->w, r->h, spc->stride_in_bytes,
    4108                   spc->h_oversample);
     4095                                  r->w, r->h, spc->stride_in_bytes,
     4096                                  spc->h_oversample);
    41094097
    41104098            if (spc->v_oversample > 1)
    41114099               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,
    4112                   r->w, r->h, spc->stride_in_bytes,
    4113                   spc->v_oversample);
    4114 
    4115             bc->x0 = (stbtt_int16)r->x;
    4116             bc->y0 = (stbtt_int16)r->y;
    4117             bc->x1 = (stbtt_int16)(r->x + r->w);
    4118             bc->y1 = (stbtt_int16)(r->y + r->h);
    4119             bc->xadvance = scale * advance;
    4120             bc->xoff = (float)x0 * recip_h + sub_x;
    4121             bc->yoff = (float)y0 * recip_v + sub_y;
    4122             bc->xoff2 = (x0 + r->w) * recip_h + sub_x;
    4123             bc->yoff2 = (y0 + r->h) * recip_v + sub_y;
    4124          }
    4125          else {
     4100                                  r->w, r->h, spc->stride_in_bytes,
     4101                                  spc->v_oversample);
     4102
     4103            bc->x0       = (stbtt_int16)  r->x;
     4104            bc->y0       = (stbtt_int16)  r->y;
     4105            bc->x1       = (stbtt_int16) (r->x + r->w);
     4106            bc->y1       = (stbtt_int16) (r->y + r->h);
     4107            bc->xadvance =                scale * advance;
     4108            bc->xoff     =       (float)  x0 * recip_h + sub_x;
     4109            bc->yoff     =       (float)  y0 * recip_v + sub_y;
     4110            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;
     4111            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;
     4112         } else {
    41264113            return_value = 0; // if any fail, report failure
    41274114         }
     
    41404127STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)
    41414128{
    4142    stbrp_pack_rects((stbrp_context *)spc->pack_info, rects, num_rects);
     4129   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
    41434130}
    41444131
     
    41464133{
    41474134   stbtt_fontinfo info;
    4148    int i, j, n, return_value = 1;
     4135   int i,j,n, return_value; // [DEAR IMGUI] removed = 1
    41494136   //stbrp_context *context = (stbrp_context *) spc->pack_info;
    41504137   stbrp_rect    *rects;
    41514138
    41524139   // flag all characters as NOT packed
    4153    for (i = 0; i < num_ranges; ++i)
    4154       for (j = 0; j < ranges[i].num_chars; ++j)
     4140   for (i=0; i < num_ranges; ++i)
     4141      for (j=0; j < ranges[i].num_chars; ++j)
    41554142         ranges[i].chardata_for_range[j].x0 =
    41564143         ranges[i].chardata_for_range[j].y0 =
     
    41594146
    41604147   n = 0;
    4161    for (i = 0; i < num_ranges; ++i)
     4148   for (i=0; i < num_ranges; ++i)
    41624149      n += ranges[i].num_chars;
    4163 
    4164    rects = (stbrp_rect *)STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
     4150         
     4151   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);
    41654152   if (rects == NULL)
    41664153      return 0;
    41674154
    41684155   info.userdata = spc->user_allocator_context;
    4169    stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, font_index));
     4156   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));
    41704157
    41714158   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);
    41724159
    41734160   stbtt_PackFontRangesPackRects(spc, rects, n);
    4174 
     4161 
    41754162   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);
    41764163
     
    41804167
    41814168STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
    4182    int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
     4169            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
    41834170{
    41844171   stbtt_pack_range range;
    41854172   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;
    41864173   range.array_of_unicode_codepoints = NULL;
    4187    range.num_chars = num_chars_in_range;
    4188    range.chardata_for_range = chardata_for_range;
    4189    range.font_size = font_size;
     4174   range.num_chars                   = num_chars_in_range;
     4175   range.chardata_for_range          = chardata_for_range;
     4176   range.font_size                   = font_size;
    41904177   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);
     4178}
     4179
     4180STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)
     4181{
     4182   int i_ascent, i_descent, i_lineGap;
     4183   float scale;
     4184   stbtt_fontinfo info;
     4185   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));
     4186   scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);
     4187   stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);
     4188   *ascent  = (float) i_ascent  * scale;
     4189   *descent = (float) i_descent * scale;
     4190   *lineGap = (float) i_lineGap * scale;
    41914191}
    41924192
     
    41974197
    41984198   if (align_to_integer) {
    4199       float x = (float)STBTT_ifloor((*xpos + b->xoff) + 0.5f);
    4200       float y = (float)STBTT_ifloor((*ypos + b->yoff) + 0.5f);
     4199      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);
     4200      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);
    42014201      q->x0 = x;
    42024202      q->y0 = y;
    42034203      q->x1 = x + b->xoff2 - b->xoff;
    42044204      q->y1 = y + b->yoff2 - b->yoff;
    4205    }
    4206    else {
     4205   } else {
    42074206      q->x0 = *xpos + b->xoff;
    42084207      q->y0 = *ypos + b->yoff;
     
    42294228static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])
    42304229{
    4231    float q0perp = q0[1] * ray[0] - q0[0] * ray[1];
    4232    float q1perp = q1[1] * ray[0] - q1[0] * ray[1];
    4233    float q2perp = q2[1] * ray[0] - q2[0] * ray[1];
    4234    float roperp = orig[1] * ray[0] - orig[0] * ray[1];
    4235 
    4236    float a = q0perp - 2 * q1perp + q2perp;
     4230   float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
     4231   float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
     4232   float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
     4233   float roperp = orig[1]*ray[0] - orig[0]*ray[1];
     4234
     4235   float a = q0perp - 2*q1perp + q2perp;
    42374236   float b = q1perp - q0perp;
    42384237   float c = q0perp - roperp;
     
    42424241
    42434242   if (a != 0.0) {
    4244       float discr = b * b - a * c;
     4243      float discr = b*b - a*c;
    42454244      if (discr > 0.0) {
    42464245         float rcpna = -1 / a;
    4247          float d = (float)STBTT_sqrt(discr);
    4248          s0 = (b + d) * rcpna;
    4249          s1 = (b - d) * rcpna;
     4246         float d = (float) STBTT_sqrt(discr);
     4247         s0 = (b+d) * rcpna;
     4248         s1 = (b-d) * rcpna;
    42504249         if (s0 >= 0.0 && s0 <= 1.0)
    42514250            num_s = 1;
     
    42554254         }
    42564255      }
    4257    }
    4258    else {
     4256   } else {
    42594257      // 2*b*s + c = 0
    42604258      // s = -c / (2*b)
     
    42674265      return 0;
    42684266   else {
    4269       float rcp_len2 = 1 / (ray[0] * ray[0] + ray[1] * ray[1]);
     4267      float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
    42704268      float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
    42714269
    4272       float q0d = q0[0] * rayn_x + q0[1] * rayn_y;
    4273       float q1d = q1[0] * rayn_x + q1[1] * rayn_y;
    4274       float q2d = q2[0] * rayn_x + q2[1] * rayn_y;
    4275       float rod = orig[0] * rayn_x + orig[1] * rayn_y;
     4270      float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;
     4271      float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;
     4272      float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;
     4273      float rod = orig[0]*rayn_x + orig[1]*rayn_y;
    42764274
    42774275      float q10d = q1d - q0d;
     
    42794277      float q0rd = q0d - rod;
    42804278
    4281       hits[0][0] = q0rd + s0 * (2.0f - 2.0f*s0)*q10d + s0 * s0*q20d;
    4282       hits[0][1] = a * s0 + b;
     4279      hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
     4280      hits[0][1] = a*s0+b;
    42834281
    42844282      if (num_s > 1) {
    4285          hits[1][0] = q0rd + s1 * (2.0f - 2.0f*s1)*q10d + s1 * s1*q20d;
    4286          hits[1][1] = a * s1 + b;
     4283         hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
     4284         hits[1][1] = a*s1+b;
    42874285         return 2;
    4288       }
    4289       else {
     4286      } else {
    42904287         return 1;
    42914288      }
     
    43064303
    43074304   orig[0] = x;
    4308    orig[1] = y;
     4305   //orig[1] = y; // [DEAR IMGUI] commmented double assignment
    43094306
    43104307   // make sure y never passes through a vertex of the shape
    4311    y_frac = (float)STBTT_fmod(y, 1.0f);
     4308   y_frac = (float) STBTT_fmod(y, 1.0f);
    43124309   if (y_frac < 0.01f)
    43134310      y += 0.01f;
     
    43174314
    43184315   // test a ray from (-infinity,y) to (x,y)
    4319    for (i = 0; i < nverts; ++i) {
     4316   for (i=0; i < nverts; ++i) {
    43204317      if (verts[i].type == STBTT_vline) {
    4321          int x0 = (int)verts[i - 1].x, y0 = (int)verts[i - 1].y;
    4322          int x1 = (int)verts[i].x, y1 = (int)verts[i].y;
    4323          if (y > STBTT_min(y0, y1) && y < STBTT_max(y0, y1) && x > STBTT_min(x0, x1)) {
    4324             float x_inter = (y - y0) / (y1 - y0) * (x1 - x0) + x0;
    4325             if (x_inter < x)
     4318         int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;
     4319         int x1 = (int) verts[i  ].x, y1 = (int) verts[i  ].y;
     4320         if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
     4321            float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
     4322            if (x_inter < x) 
    43264323               winding += (y0 < y1) ? 1 : -1;
    43274324         }
    43284325      }
    43294326      if (verts[i].type == STBTT_vcurve) {
    4330          int x0 = (int)verts[i - 1].x, y0 = (int)verts[i - 1].y;
    4331          int x1 = (int)verts[i].cx, y1 = (int)verts[i].cy;
    4332          int x2 = (int)verts[i].x, y2 = (int)verts[i].y;
    4333          int ax = STBTT_min(x0, STBTT_min(x1, x2)), ay = STBTT_min(y0, STBTT_min(y1, y2));
    4334          int by = STBTT_max(y0, STBTT_max(y1, y2));
     4327         int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;
     4328         int x1 = (int) verts[i  ].cx, y1 = (int) verts[i  ].cy;
     4329         int x2 = (int) verts[i  ].x , y2 = (int) verts[i  ].y ;
     4330         int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
     4331         int by = STBTT_max(y0,STBTT_max(y1,y2));
    43354332         if (y > ay && y < by && x > ax) {
    4336             float q0[2], q1[2], q2[2];
     4333            float q0[2],q1[2],q2[2];
    43374334            float hits[2][2];
    43384335            q0[0] = (float)x0;
     
    43424339            q2[0] = (float)x2;
    43434340            q2[1] = (float)y2;
    4344             if (equal(q0, q1) || equal(q1, q2)) {
    4345                x0 = (int)verts[i - 1].x;
    4346                y0 = (int)verts[i - 1].y;
    4347                x1 = (int)verts[i].x;
    4348                y1 = (int)verts[i].y;
    4349                if (y > STBTT_min(y0, y1) && y < STBTT_max(y0, y1) && x > STBTT_min(x0, x1)) {
    4350                   float x_inter = (y - y0) / (y1 - y0) * (x1 - x0) + x0;
    4351                   if (x_inter < x)
     4341            if (equal(q0,q1) || equal(q1,q2)) {
     4342               x0 = (int)verts[i-1].x;
     4343               y0 = (int)verts[i-1].y;
     4344               x1 = (int)verts[i  ].x;
     4345               y1 = (int)verts[i  ].y;
     4346               if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
     4347                  float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
     4348                  if (x_inter < x) 
    43524349                     winding += (y0 < y1) ? 1 : -1;
    43534350               }
    4354             }
    4355             else {
     4351            } else {
    43564352               int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
    43574353               if (num_hits >= 1)
     
    43624358                     winding += (hits[1][1] < 0 ? -1 : 1);
    43634359            }
    4364          }
     4360         } 
    43654361      }
    43664362   }
     
    43684364}
    43694365
    4370 static float stbtt__cuberoot(float x)
     4366static float stbtt__cuberoot( float x )
    43714367{
    43724368   if (x<0)
    4373       return -(float)STBTT_pow(-x, 1.0f / 3.0f);
     4369      return -(float) STBTT_pow(-x,1.0f/3.0f);
    43744370   else
    4375       return  (float)STBTT_pow(x, 1.0f / 3.0f);
     4371      return  (float) STBTT_pow( x,1.0f/3.0f);
    43764372}
    43774373
     
    43794375static int stbtt__solve_cubic(float a, float b, float c, float* r)
    43804376{
    4381    float s = -a / 3;
    4382    float p = b - a * a / 3;
    4383    float q = a * (2 * a*a - 9 * b) / 27 + c;
    4384    float p3 = p * p*p;
    4385    float d = q * q + 4 * p3 / 27;
    4386    if (d >= 0) {
    4387       float z = (float)STBTT_sqrt(d);
    4388       float u = (-q + z) / 2;
    4389       float v = (-q - z) / 2;
    4390       u = stbtt__cuberoot(u);
    4391       v = stbtt__cuberoot(v);
    4392       r[0] = s + u + v;
    4393       return 1;
    4394    }
    4395    else {
    4396       float u = (float)STBTT_sqrt(-p / 3);
    4397       float v = (float)STBTT_acos(-STBTT_sqrt(-27 / p3) * q / 2) / 3; // p3 must be negative, since d is negative
    4398       float m = (float)STBTT_cos(v);
    4399       float n = (float)STBTT_cos(v - 3.141592 / 2)*1.732050808f;
    4400       r[0] = s + u * 2 * m;
    4401       r[1] = s - u * (m + n);
    4402       r[2] = s - u * (m - n);
     4377        float s = -a / 3;
     4378        float p = b - a*a / 3;
     4379        float q = a * (2*a*a - 9*b) / 27 + c;
     4380   float p3 = p*p*p;
     4381        float d = q*q + 4*p3 / 27;
     4382        if (d >= 0) {
     4383                float z = (float) STBTT_sqrt(d);
     4384                float u = (-q + z) / 2;
     4385                float v = (-q - z) / 2;
     4386                u = stbtt__cuberoot(u);
     4387                v = stbtt__cuberoot(v);
     4388                r[0] = s + u + v;
     4389                return 1;
     4390        } else {
     4391           float u = (float) STBTT_sqrt(-p/3);
     4392           float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
     4393           float m = (float) STBTT_cos(v);
     4394      float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
     4395           r[0] = s + u * 2 * m;
     4396           r[1] = s - u * (m + n);
     4397           r[2] = s - u * (m - n);
    44034398
    44044399      //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f);  // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
    44054400      //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
    44064401      //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
    4407       return 3;
     4402        return 3;
    44084403   }
    44094404}
     
    44124407{
    44134408   float scale_x = scale, scale_y = scale;
    4414    int ix0, iy0, ix1, iy1;
    4415    int w, h;
     4409   int ix0,iy0,ix1,iy1;
     4410   int w,h;
    44164411   unsigned char *data;
    44174412
     
    44234418   }
    44244419
    4425    stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f, 0.0f, &ix0, &iy0, &ix1, &iy1);
     4420   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
    44264421
    44274422   // if empty, return NULL
     
    44374432   h = (iy1 - iy0);
    44384433
    4439    if (width) *width = w;
     4434   if (width ) *width = w;
    44404435   if (height) *height = h;
    4441    if (xoff) *xoff = ix0;
    4442    if (yoff) *yoff = iy0;
     4436   if (xoff  ) *xoff  = ix0;
     4437   if (yoff  ) *yoff  = iy0;
    44434438
    44444439   // invert for y-downwards bitmaps
    44454440   scale_y = -scale_y;
    4446 
     4441     
    44474442   {
    4448       int x, y, i, j;
     4443      int x,y,i,j;
    44494444      float *precompute;
    44504445      stbtt_vertex *verts;
    44514446      int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
    4452       data = (unsigned char *)STBTT_malloc(w * h, info->userdata);
    4453       precompute = (float *)STBTT_malloc(num_verts * sizeof(float), info->userdata);
    4454 
    4455       for (i = 0, j = num_verts - 1; i < num_verts; j = i++) {
     4447      data = (unsigned char *) STBTT_malloc(w * h, info->userdata);
     4448      precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);
     4449
     4450      for (i=0,j=num_verts-1; i < num_verts; j=i++) {
    44564451         if (verts[i].type == STBTT_vline) {
    44574452            float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
    44584453            float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
    4459             float dist = (float)STBTT_sqrt((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0));
     4454            float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
    44604455            precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
    4461          }
    4462          else if (verts[i].type == STBTT_vcurve) {
     4456         } else if (verts[i].type == STBTT_vcurve) {
    44634457            float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
    44644458            float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
    44654459            float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
    4466             float bx = x0 - 2 * x1 + x2, by = y0 - 2 * y1 + y2;
    4467             float len2 = bx * bx + by * by;
     4460            float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
     4461            float len2 = bx*bx + by*by;
    44684462            if (len2 != 0.0f)
    4469                precompute[i] = 1.0f / (bx*bx + by * by);
     4463               precompute[i] = 1.0f / (bx*bx + by*by);
    44704464            else
    44714465               precompute[i] = 0.0f;
    4472          }
    4473          else
     4466         } else
    44744467            precompute[i] = 0.0f;
    44754468      }
    44764469
    4477       for (y = iy0; y < iy1; ++y) {
    4478          for (x = ix0; x < ix1; ++x) {
     4470      for (y=iy0; y < iy1; ++y) {
     4471         for (x=ix0; x < ix1; ++x) {
    44794472            float val;
    44804473            float min_dist = 999999.0f;
    4481             float sx = (float)x + 0.5f;
    4482             float sy = (float)y + 0.5f;
     4474            float sx = (float) x + 0.5f;
     4475            float sy = (float) y + 0.5f;
    44834476            float x_gspace = (sx / scale_x);
    44844477            float y_gspace = (sy / scale_y);
     
    44864479            int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path
    44874480
    4488             for (i = 0; i < num_verts; ++i) {
     4481            for (i=0; i < num_verts; ++i) {
    44894482               float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
    44904483
    44914484               // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
    4492                float dist2 = (x0 - sx)*(x0 - sx) + (y0 - sy)*(y0 - sy);
     4485               float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
    44934486               if (dist2 < min_dist*min_dist)
    4494                   min_dist = (float)STBTT_sqrt(dist2);
     4487                  min_dist = (float) STBTT_sqrt(dist2);
    44954488
    44964489               if (verts[i].type == STBTT_vline) {
    4497                   float x1 = verts[i - 1].x*scale_x, y1 = verts[i - 1].y*scale_y;
     4490                  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
    44984491
    44994492                  // coarse culling against bbox
    45004493                  //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
    45014494                  //    sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
    4502                   float dist = (float)STBTT_fabs((x1 - x0)*(y0 - sy) - (y1 - y0)*(x0 - sx)) * precompute[i];
     4495                  float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
    45034496                  STBTT_assert(i != 0);
    45044497                  if (dist < min_dist) {
     
    45064499                     // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
    45074500                     // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
    4508                      float dx = x1 - x0, dy = y1 - y0;
    4509                      float px = x0 - sx, py = y0 - sy;
     4501                     float dx = x1-x0, dy = y1-y0;
     4502                     float px = x0-sx, py = y0-sy;
    45104503                     // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy
    45114504                     // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
    4512                      float t = -(px*dx + py * dy) / (dx*dx + dy * dy);
     4505                     float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
    45134506                     if (t >= 0.0f && t <= 1.0f)
    45144507                        min_dist = dist;
    45154508                  }
    4516                }
    4517                else if (verts[i].type == STBTT_vcurve) {
    4518                   float x2 = verts[i - 1].x *scale_x, y2 = verts[i - 1].y *scale_y;
    4519                   float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
    4520                   float box_x0 = STBTT_min(STBTT_min(x0, x1), x2);
    4521                   float box_y0 = STBTT_min(STBTT_min(y0, y1), y2);
    4522                   float box_x1 = STBTT_max(STBTT_max(x0, x1), x2);
    4523                   float box_y1 = STBTT_max(STBTT_max(y0, y1), y2);
     4509               } else if (verts[i].type == STBTT_vcurve) {
     4510                  float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
     4511                  float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;
     4512                  float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
     4513                  float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
     4514                  float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
     4515                  float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
    45244516                  // coarse culling against bbox to avoid computing cubic unnecessarily
    4525                   if (sx > box_x0 - min_dist && sx < box_x1 + min_dist && sy > box_y0 - min_dist && sy < box_y1 + min_dist) {
    4526                      int num = 0;
    4527                      float ax = x1 - x0, ay = y1 - y0;
    4528                      float bx = x0 - 2 * x1 + x2, by = y0 - 2 * y1 + y2;
     4517                  if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
     4518                     int num=0;
     4519                     float ax = x1-x0, ay = y1-y0;
     4520                     float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
    45294521                     float mx = x0 - sx, my = y0 - sy;
    4530                      float res[3], px, py, t, it;
     4522                     float res[3],px,py,t,it;
    45314523                     float a_inv = precompute[i];
    45324524                     if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
    4533                         float a = 3 * (ax*bx + ay * by);
    4534                         float b = 2 * (ax*ax + ay * ay) + (mx*bx + my * by);
    4535                         float c = mx * ax + my * ay;
     4525                        float a = 3*(ax*bx + ay*by);
     4526                        float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
     4527                        float c = mx*ax+my*ay;
    45364528                        if (a == 0.0) { // if a is 0, it's linear
    45374529                           if (b != 0.0) {
    4538                               res[num++] = -c / b;
     4530                              res[num++] = -c/b;
    45394531                           }
    4540                         }
    4541                         else {
    4542                            float discriminant = b * b - 4 * a*c;
     4532                        } else {
     4533                           float discriminant = b*b - 4*a*c;
    45434534                           if (discriminant < 0)
    45444535                              num = 0;
    45454536                           else {
    4546                               float root = (float)STBTT_sqrt(discriminant);
    4547                               res[0] = (-b - root) / (2 * a);
    4548                               res[1] = (-b + root) / (2 * a);
     4537                              float root = (float) STBTT_sqrt(discriminant);
     4538                              res[0] = (-b - root)/(2*a);
     4539                              res[1] = (-b + root)/(2*a);
    45494540                              num = 2; // don't bother distinguishing 1-solution case, as code below will still work
    45504541                           }
    45514542                        }
    4552                      }
    4553                      else {
    4554                         float b = 3 * (ax*bx + ay * by) * a_inv; // could precompute this as it doesn't depend on sample point
    4555                         float c = (2 * (ax*ax + ay * ay) + (mx*bx + my * by)) * a_inv;
    4556                         float d = (mx*ax + my * ay) * a_inv;
     4543                     } else {
     4544                        float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
     4545                        float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
     4546                        float d = (mx*ax+my*ay) * a_inv;
    45574547                        num = stbtt__solve_cubic(b, c, d, res);
    45584548                     }
    45594549                     if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
    45604550                        t = res[0], it = 1.0f - t;
    4561                         px = it * it*x0 + 2 * t*it*x1 + t * t*x2;
    4562                         py = it * it*y0 + 2 * t*it*y1 + t * t*y2;
    4563                         dist2 = (px - sx)*(px - sx) + (py - sy)*(py - sy);
     4551                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
     4552                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
     4553                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
    45644554                        if (dist2 < min_dist * min_dist)
    4565                            min_dist = (float)STBTT_sqrt(dist2);
     4555                           min_dist = (float) STBTT_sqrt(dist2);
    45664556                     }
    45674557                     if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
    45684558                        t = res[1], it = 1.0f - t;
    4569                         px = it * it*x0 + 2 * t*it*x1 + t * t*x2;
    4570                         py = it * it*y0 + 2 * t*it*y1 + t * t*y2;
    4571                         dist2 = (px - sx)*(px - sx) + (py - sy)*(py - sy);
     4559                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
     4560                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
     4561                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
    45724562                        if (dist2 < min_dist * min_dist)
    4573                            min_dist = (float)STBTT_sqrt(dist2);
     4563                           min_dist = (float) STBTT_sqrt(dist2);
    45744564                     }
    45754565                     if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
    45764566                        t = res[2], it = 1.0f - t;
    4577                         px = it * it*x0 + 2 * t*it*x1 + t * t*x2;
    4578                         py = it * it*y0 + 2 * t*it*y1 + t * t*y2;
    4579                         dist2 = (px - sx)*(px - sx) + (py - sy)*(py - sy);
     4567                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;
     4568                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;
     4569                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
    45804570                        if (dist2 < min_dist * min_dist)
    4581                            min_dist = (float)STBTT_sqrt(dist2);
     4571                           min_dist = (float) STBTT_sqrt(dist2);
    45824572                     }
    45834573                  }
     
    45914581            else if (val > 255)
    45924582               val = 255;
    4593             data[(y - iy0)*w + (x - ix0)] = (unsigned char)val;
     4583            data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;
    45944584         }
    45954585      }
     
    45984588   }
    45994589   return data;
    4600 }
     4590}   
    46014591
    46024592STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
     
    46164606
    46174607// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
    4618 static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
    4619 {
    4620    stbtt_int32 i = 0;
     4608static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) 
     4609{
     4610   stbtt_int32 i=0;
    46214611
    46224612   // convert utf16 to utf8 and compare the results while converting
    46234613   while (len2) {
    4624       stbtt_uint16 ch = s2[0] * 256 + s2[1];
     4614      stbtt_uint16 ch = s2[0]*256 + s2[1];
    46254615      if (ch < 0x80) {
    46264616         if (i >= len1) return -1;
    46274617         if (s1[i++] != ch) return -1;
    4628       }
    4629       else if (ch < 0x800) {
    4630          if (i + 1 >= len1) return -1;
     4618      } else if (ch < 0x800) {
     4619         if (i+1 >= len1) return -1;
    46314620         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;
    46324621         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;
    4633       }
    4634       else if (ch >= 0xd800 && ch < 0xdc00) {
     4622      } else if (ch >= 0xd800 && ch < 0xdc00) {
    46354623         stbtt_uint32 c;
    4636          stbtt_uint16 ch2 = s2[2] * 256 + s2[3];
    4637          if (i + 3 >= len1) return -1;
     4624         stbtt_uint16 ch2 = s2[2]*256 + s2[3];
     4625         if (i+3 >= len1) return -1;
    46384626         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;
    46394627         if (s1[i++] != 0xf0 + (c >> 18)) return -1;
    46404628         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;
    4641          if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1;
    4642          if (s1[i++] != 0x80 + ((c) & 0x3f)) return -1;
     4629         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;
     4630         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;
    46434631         s2 += 2; // plus another 2 below
    46444632         len2 -= 2;
    4645       }
    4646       else if (ch >= 0xdc00 && ch < 0xe000) {
     4633      } else if (ch >= 0xdc00 && ch < 0xe000) {
    46474634         return -1;
    4648       }
    4649       else {
    4650          if (i + 2 >= len1) return -1;
     4635      } else {
     4636         if (i+2 >= len1) return -1;
    46514637         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;
    46524638         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;
    4653          if (s1[i++] != 0x80 + ((ch) & 0x3f)) return -1;
     4639         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;
    46544640      }
    46554641      s2 += 2;
     
    46594645}
    46604646
    4661 static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
    4662 {
    4663    return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*)s1, len1, (stbtt_uint8*)s2, len2);
     4647static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) 
     4648{
     4649   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
    46644650}
    46654651
     
    46684654STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)
    46694655{
    4670    stbtt_int32 i, count, stringOffset;
     4656   stbtt_int32 i,count,stringOffset;
    46714657   stbtt_uint8 *fc = font->data;
    46724658   stbtt_uint32 offset = font->fontstart;
     
    46744660   if (!nm) return NULL;
    46754661
    4676    count = ttUSHORT(fc + nm + 2);
    4677    stringOffset = nm + ttUSHORT(fc + nm + 4);
    4678    for (i = 0; i < count; ++i) {
     4662   count = ttUSHORT(fc+nm+2);
     4663   stringOffset = nm + ttUSHORT(fc+nm+4);
     4664   for (i=0; i < count; ++i) {
    46794665      stbtt_uint32 loc = nm + 6 + 12 * i;
    4680       if (platformID == ttUSHORT(fc + loc + 0) && encodingID == ttUSHORT(fc + loc + 2)
    4681          && languageID == ttUSHORT(fc + loc + 4) && nameID == ttUSHORT(fc + loc + 6)) {
    4682          *length = ttUSHORT(fc + loc + 8);
    4683          return (const char *)(fc + stringOffset + ttUSHORT(fc + loc + 10));
     4666      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)
     4667          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {
     4668         *length = ttUSHORT(fc+loc+8);
     4669         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));
    46844670      }
    46854671   }
     
    46904676{
    46914677   stbtt_int32 i;
    4692    stbtt_int32 count = ttUSHORT(fc + nm + 2);
    4693    stbtt_int32 stringOffset = nm + ttUSHORT(fc + nm + 4);
    4694 
    4695    for (i = 0; i < count; ++i) {
     4678   stbtt_int32 count = ttUSHORT(fc+nm+2);
     4679   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);
     4680
     4681   for (i=0; i < count; ++i) {
    46964682      stbtt_uint32 loc = nm + 6 + 12 * i;
    4697       stbtt_int32 id = ttUSHORT(fc + loc + 6);
     4683      stbtt_int32 id = ttUSHORT(fc+loc+6);
    46984684      if (id == target_id) {
    46994685         // find the encoding
    4700          stbtt_int32 platform = ttUSHORT(fc + loc + 0), encoding = ttUSHORT(fc + loc + 2), language = ttUSHORT(fc + loc + 4);
     4686         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);
    47014687
    47024688         // is this a Unicode encoding?
    47034689         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {
    4704             stbtt_int32 slen = ttUSHORT(fc + loc + 8);
    4705             stbtt_int32 off = ttUSHORT(fc + loc + 10);
     4690            stbtt_int32 slen = ttUSHORT(fc+loc+8);
     4691            stbtt_int32 off = ttUSHORT(fc+loc+10);
    47064692
    47074693            // check if there's a prefix match
    4708             stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc + stringOffset + off, slen);
     4694            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);
    47094695            if (matchlen >= 0) {
    47104696               // check for target_id+1 immediately following, with same encoding & language
    4711                if (i + 1 < count && ttUSHORT(fc + loc + 12 + 6) == next_id && ttUSHORT(fc + loc + 12) == platform && ttUSHORT(fc + loc + 12 + 2) == encoding && ttUSHORT(fc + loc + 12 + 4) == language) {
    4712                   slen = ttUSHORT(fc + loc + 12 + 8);
    4713                   off = ttUSHORT(fc + loc + 12 + 10);
     4697               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {
     4698                  slen = ttUSHORT(fc+loc+12+8);
     4699                  off = ttUSHORT(fc+loc+12+10);
    47144700                  if (slen == 0) {
    47154701                     if (matchlen == nlen)
    47164702                        return 1;
    4717                   }
    4718                   else if (matchlen < nlen && name[matchlen] == ' ') {
     4703                  } else if (matchlen < nlen && name[matchlen] == ' ') {
    47194704                     ++matchlen;
    4720                      if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*)(name + matchlen), nlen - matchlen, (char*)(fc + stringOffset + off), slen))
     4705                     if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
    47214706                        return 1;
    47224707                  }
    4723                }
    4724                else {
     4708               } else {
    47254709                  // if nothing immediately following
    47264710                  if (matchlen == nlen)
     
    47384722static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)
    47394723{
    4740    stbtt_int32 nlen = (stbtt_int32)STBTT_strlen((char *)name);
    4741    stbtt_uint32 nm, hd;
    4742    if (!stbtt__isfont(fc + offset)) return 0;
     4724   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);
     4725   stbtt_uint32 nm,hd;
     4726   if (!stbtt__isfont(fc+offset)) return 0;
    47434727
    47444728   // check italics/bold/underline flags in macStyle...
    47454729   if (flags) {
    47464730      hd = stbtt__find_table(fc, offset, "head");
    4747       if ((ttUSHORT(fc + hd + 44) & 7) != (flags & 7)) return 0;
     4731      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;
    47484732   }
    47494733
     
    47544738      // if we checked the macStyle flags, then just check the family and ignore the subfamily
    47554739      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;
    4756       if (stbtt__matchpair(fc, nm, name, nlen, 1, -1))  return 1;
    4757       if (stbtt__matchpair(fc, nm, name, nlen, 3, -1))  return 1;
    4758    }
    4759    else {
     4740      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;
     4741      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;
     4742   } else {
    47604743      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;
    4761       if (stbtt__matchpair(fc, nm, name, nlen, 1, 2))  return 1;
    4762       if (stbtt__matchpair(fc, nm, name, nlen, 3, -1))  return 1;
     4744      if (stbtt__matchpair(fc, nm, name, nlen,  1, 2))  return 1;
     4745      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;
    47634746   }
    47644747
     
    47694752{
    47704753   stbtt_int32 i;
    4771    for (i = 0;; ++i) {
     4754   for (i=0;;++i) {
    47724755      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);
    47734756      if (off < 0) return off;
    4774       if (stbtt__matches((stbtt_uint8 *)font_collection, off, (stbtt_uint8*)name_utf8, flags))
     4757      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))
    47754758         return off;
    47764759   }
     
    47834766
    47844767STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
    4785    float pixel_height, unsigned char *pixels, int pw, int ph,
    4786    int first_char, int num_chars, stbtt_bakedchar *chardata)
    4787 {
    4788    return stbtt_BakeFontBitmap_internal((unsigned char *)data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
     4768                                float pixel_height, unsigned char *pixels, int pw, int ph,
     4769                                int first_char, int num_chars, stbtt_bakedchar *chardata)
     4770{
     4771   return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
    47894772}
    47904773
    47914774STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
    47924775{
    4793    return stbtt_GetFontOffsetForIndex_internal((unsigned char *)data, index);
     4776   return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);   
    47944777}
    47954778
    47964779STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
    47974780{
    4798    return stbtt_GetNumberOfFonts_internal((unsigned char *)data);
     4781   return stbtt_GetNumberOfFonts_internal((unsigned char *) data);
    47994782}
    48004783
    48014784STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)
    48024785{
    4803    return stbtt_InitFont_internal(info, (unsigned char *)data, offset);
     4786   return stbtt_InitFont_internal(info, (unsigned char *) data, offset);
    48044787}
    48054788
    48064789STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)
    48074790{
    4808    return stbtt_FindMatchingFont_internal((unsigned char *)fontdata, (char *)name, flags);
     4791   return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);
    48094792}
    48104793
    48114794STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
    48124795{
    4813    return stbtt_CompareUTF8toUTF16_bigendian_internal((char *)s1, len1, (char *)s2, len2);
     4796   return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);
    48144797}
    48154798
     
    48844867ALTERNATIVE A - MIT License
    48854868Copyright (c) 2017 Sean Barrett
    4886 Permission is hereby granted, free of charge, to any person obtaining a copy of
    4887 this software and associated documentation files (the "Software"), to deal in
    4888 the Software without restriction, including without limitation the rights to
    4889 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
    4890 of the Software, and to permit persons to whom the Software is furnished to do
     4869Permission is hereby granted, free of charge, to any person obtaining a copy of 
     4870this software and associated documentation files (the "Software"), to deal in 
     4871the Software without restriction, including without limitation the rights to 
     4872use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
     4873of the Software, and to permit persons to whom the Software is furnished to do 
    48914874so, subject to the following conditions:
    4892 The above copyright notice and this permission notice shall be included in all
     4875The above copyright notice and this permission notice shall be included in all 
    48934876copies or substantial portions of the Software.
    4894 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    4895 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    4896 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    4897 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    4898 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    4899 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     4877THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
     4878IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
     4879FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
     4880AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
     4881LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
     4882OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
    49004883SOFTWARE.
    49014884------------------------------------------------------------------------------
    49024885ALTERNATIVE B - Public Domain (www.unlicense.org)
    49034886This is free and unencumbered software released into the public domain.
    4904 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
    4905 software, either in source code form or as a compiled binary, for any purpose,
     4887Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 
     4888software, either in source code form or as a compiled binary, for any purpose, 
    49064889commercial or non-commercial, and by any means.
    4907 In jurisdictions that recognize copyright laws, the author or authors of this
    4908 software dedicate any and all copyright interest in the software to the public
    4909 domain. We make this dedication for the benefit of the public at large and to
    4910 the detriment of our heirs and successors. We intend this dedication to be an
    4911 overt act of relinquishment in perpetuity of all present and future rights to
     4890In jurisdictions that recognize copyright laws, the author or authors of this 
     4891software dedicate any and all copyright interest in the software to the public 
     4892domain. We make this dedication for the benefit of the public at large and to 
     4893the detriment of our heirs and successors. We intend this dedication to be an 
     4894overt act of relinquishment in perpetuity of all present and future rights to 
    49124895this software under copyright law.
    4913 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    4914 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    4915 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    4916 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
    4917 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     4896THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
     4897IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
     4898FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
     4899AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
     4900ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    49184901WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    49194902------------------------------------------------------------------------------
  • OpenGLReference.vcxproj

    r78c3045 re66fd66  
    145145    <ClCompile Include="IMGUI\imgui_demo.cpp" />
    146146    <ClCompile Include="IMGUI\imgui_draw.cpp" />
    147     <ClCompile Include="imgui_impl_glfw_gl3.cpp" />
     147    <ClCompile Include="IMGUI\imgui_impl_glfw.cpp" />
     148    <ClCompile Include="IMGUI\imgui_impl_opengl3.cpp" />
     149    <ClCompile Include="IMGUI\imgui_widgets.cpp" />
    148150    <ClCompile Include="logger.cpp" />
    149151    <ClCompile Include="new-game.cpp" />
     
    154156    <ClInclude Include="crash-logger.hpp" />
    155157    <ClInclude Include="FileStackWalker.h" />
     158    <ClInclude Include="IMGUI\imconfig.h" />
    156159    <ClInclude Include="IMGUI\imgui.h" />
     160    <ClInclude Include="IMGUI\imgui_impl_glfw.h" />
     161    <ClInclude Include="IMGUI\imgui_impl_opengl3.h" />
    157162    <ClInclude Include="IMGUI\imgui_internal.h" />
    158     <ClInclude Include="IMGUI\stb_rect_pack.h" />
    159     <ClInclude Include="IMGUI\stb_textedit.h" />
    160     <ClInclude Include="IMGUI\stb_truetype.h" />
    161     <ClInclude Include="imgui_impl_glfw_gl3.h" />
    162     <ClInclude Include="logger.h" />
     163    <ClInclude Include="IMGUI\imstb_rectpack.h" />
     164    <ClInclude Include="IMGUI\imstb_textedit.h" />
     165    <ClInclude Include="IMGUI\imstb_truetype.h" />
     166    <ClInclude Include="logger.hpp" />
    163167    <ClInclude Include="StackWalker.h" />
    164168    <ClInclude Include="stb_image.h" />
     
    180184    <None Include="gl-shaders\ship.frag" />
    181185    <None Include="gl-shaders\ship.vert" />
    182     <None Include="texture.frag" />
    183     <None Include="texture.vert" />
    184186  </ItemGroup>
    185187  <ItemGroup>
  • new-game.cpp

    r78c3045 re66fd66  
    99
    1010#include "IMGUI/imgui.h"
    11 #include "imgui_impl_glfw_gl3.h"
     11#include "IMGUI/imgui_impl_glfw.h"
     12#include "IMGUI/imgui_impl_opengl3.h"
    1213
    1314#include <GL/glew.h>
     
    3637using namespace glm;
    3738
    38 enum State {
    39    STATE_MAIN_MENU,
    40    STATE_GAME,
     39enum class State {
     40   MAIN_MENU,
     41   GAME,
    4142};
    4243
    43 enum Event {
    44    EVENT_GO_TO_MAIN_MENU,
    45    EVENT_GO_TO_GAME,
    46    EVENT_QUIT,
     44enum class Event {
     45   GO_TO_MAIN_MENU,
     46   GO_TO_GAME,
     47   QUIT,
    4748};
    4849
    4950/*** START OF REFACTORED CODE ***/
    50 enum ObjectType {
    51    TYPE_SHIP,
    52    TYPE_ASTEROID,
    53    TYPE_LASER,
    54    TYPE_EXPLOSION,
     51enum class ObjectType {
     52   SHIP,
     53   ASTEROID,
     54   LASER,
     55   EXPLOSION,
    5556};
    5657
    57 enum AttribType {
    58    ATTRIB_UNIFORM,
    59    ATTRIB_OBJECT_VARYING,
    60    ATTRIB_POINT_VARYING,
     58enum class AttribType {
     59   UNIFORM,
     60   OBJECT_VARYING,
     61   POINT_VARYING,
    6162};
    6263
     
    248249
    249250#define NUM_KEYS (512)
    250 #define ONE_DEG_IN_RAD ((2.0f * M_PI) / 360.0f) // 0.017444444 (maybe make this a const instead)
    251251#define TARGET_FPS 60.0f
    252252
     
    332332      return 1;
    333333   }
     334
     335   string glsl_version = "#version 410";
    334336
    335337#ifdef MAC
     
    411413   IMGUI_CHECKVERSION();
    412414   ImGui::CreateContext();
     415
    413416   ImGuiIO& io = ImGui::GetIO(); (void)io;
    414    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;  // Enable Keyboard Controls
    415    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;   // Enable Gamepad Controls
    416    ImGui_ImplGlfwGL3_Init(window, true);
    417 
    418    // Setup style
     417   //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
     418   //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
     419
     420   // Setup Dear ImGui style
    419421   ImGui::StyleColorsDark();
    420422   //ImGui::StyleColorsClassic();
     423
     424   // Setup Platform/Renderer backends
     425   ImGui_ImplGlfw_InitForOpenGL(window, true);
     426   ImGui_ImplOpenGL3_Init(glsl_version.c_str());
    421427
    422428   glfwSetMouseButtonCallback(window, mouse_button_callback);
     
    497503   map<ObjectType, ShaderModelGroup> modelGroups;
    498504
    499    modelGroups[TYPE_SHIP] = createModelGroup(
     505   modelGroups[ObjectType::SHIP] = createModelGroup(
    500506      loadShaderProgram("gl-shaders/ship.vert", "gl-shaders/ship.frag"));
    501    shaderBufferInfo[modelGroups[TYPE_SHIP].shaderProgram] = BufferInfo(); // temporary
    502 
    503    defineModelGroupAttrib(modelGroups[TYPE_SHIP], "vertex_position", ATTRIB_POINT_VARYING,
     507   shaderBufferInfo[modelGroups[ObjectType::SHIP].shaderProgram] = BufferInfo(); // temporary
     508
     509   defineModelGroupAttrib(modelGroups[ObjectType::SHIP], "vertex_position", AttribType::POINT_VARYING,
    504510      3, GL_FLOAT, offset_of(&SceneObject::points));
    505    defineModelGroupAttrib(modelGroups[TYPE_SHIP], "vertex_color", ATTRIB_POINT_VARYING,
     511   defineModelGroupAttrib(modelGroups[ObjectType::SHIP], "vertex_color", AttribType::POINT_VARYING,
    506512      3, GL_FLOAT, offset_of(&SceneObject::colors));
    507    defineModelGroupAttrib(modelGroups[TYPE_SHIP], "vertex_normal", ATTRIB_POINT_VARYING,
     513   defineModelGroupAttrib(modelGroups[ObjectType::SHIP], "vertex_normal", AttribType::POINT_VARYING,
    508514      3, GL_FLOAT, offset_of(&SceneObject::normals));
    509    defineModelGroupAttrib(modelGroups[TYPE_SHIP], "ubo_index", ATTRIB_OBJECT_VARYING,
     515   defineModelGroupAttrib(modelGroups[ObjectType::SHIP], "ubo_index", AttribType::OBJECT_VARYING,
    510516      1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset));
    511517
    512    defineModelGroupUniform(modelGroups[TYPE_SHIP], "view", ATTRIB_UNIFORM,
     518   defineModelGroupUniform(modelGroups[ObjectType::SHIP], "view", AttribType::UNIFORM,
    513519      1, UNIFORM_MATRIX_4F, value_ptr(view_mat));
    514    defineModelGroupUniform(modelGroups[TYPE_SHIP], "proj", ATTRIB_UNIFORM,
     520   defineModelGroupUniform(modelGroups[ObjectType::SHIP], "proj", AttribType::UNIFORM,
    515521      1, UNIFORM_MATRIX_4F, value_ptr(proj_mat));
    516522
    517    initModelGroupAttribs(modelGroups[TYPE_SHIP]);
    518 
    519    modelGroups[TYPE_ASTEROID] = createModelGroup(
     523   initModelGroupAttribs(modelGroups[ObjectType::SHIP]);
     524
     525   modelGroups[ObjectType::ASTEROID] = createModelGroup(
    520526      loadShaderProgram("gl-shaders/asteroid.vert", "gl-shaders/asteroid.frag"));
    521    shaderBufferInfo[modelGroups[TYPE_ASTEROID].shaderProgram] = BufferInfo(); // temporary
    522 
    523    defineModelGroupAttrib(modelGroups[TYPE_ASTEROID], "vertex_position", ATTRIB_POINT_VARYING,
     527   shaderBufferInfo[modelGroups[ObjectType::ASTEROID].shaderProgram] = BufferInfo(); // temporary
     528
     529   defineModelGroupAttrib(modelGroups[ObjectType::ASTEROID], "vertex_position", AttribType::POINT_VARYING,
    524530      3, GL_FLOAT, offset_of(&SceneObject::points));
    525    defineModelGroupAttrib(modelGroups[TYPE_ASTEROID], "vertex_color", ATTRIB_POINT_VARYING,
     531   defineModelGroupAttrib(modelGroups[ObjectType::ASTEROID], "vertex_color", AttribType::POINT_VARYING,
    526532      3, GL_FLOAT, offset_of(&SceneObject::colors));
    527    defineModelGroupAttrib(modelGroups[TYPE_ASTEROID], "vertex_normal", ATTRIB_POINT_VARYING,
     533   defineModelGroupAttrib(modelGroups[ObjectType::ASTEROID], "vertex_normal", AttribType::POINT_VARYING,
    528534      3, GL_FLOAT, offset_of(&SceneObject::normals));
    529    defineModelGroupAttrib(modelGroups[TYPE_ASTEROID], "ubo_index", ATTRIB_OBJECT_VARYING,
     535   defineModelGroupAttrib(modelGroups[ObjectType::ASTEROID], "ubo_index", AttribType::OBJECT_VARYING,
    530536      1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset));
    531537
    532    defineModelGroupUniform(modelGroups[TYPE_ASTEROID], "view", ATTRIB_UNIFORM,
     538   defineModelGroupUniform(modelGroups[ObjectType::ASTEROID], "view", AttribType::UNIFORM,
    533539      1, UNIFORM_MATRIX_4F, value_ptr(view_mat));
    534    defineModelGroupUniform(modelGroups[TYPE_ASTEROID], "proj", ATTRIB_UNIFORM,
     540   defineModelGroupUniform(modelGroups[ObjectType::ASTEROID], "proj", AttribType::UNIFORM,
    535541      1, UNIFORM_MATRIX_4F, value_ptr(proj_mat));
    536542
    537    initModelGroupAttribs(modelGroups[TYPE_ASTEROID]);
    538 
    539    modelGroups[TYPE_LASER] = createModelGroup(
     543   initModelGroupAttribs(modelGroups[ObjectType::ASTEROID]);
     544
     545   modelGroups[ObjectType::LASER] = createModelGroup(
    540546      loadShaderProgram("gl-shaders/laser.vert", "gl-shaders/laser.frag"));
    541    shaderBufferInfo[modelGroups[TYPE_LASER].shaderProgram] = BufferInfo(); // temporary
    542 
    543    defineModelGroupAttrib(modelGroups[TYPE_LASER], "vertex_position", ATTRIB_POINT_VARYING,
     547   shaderBufferInfo[modelGroups[ObjectType::LASER].shaderProgram] = BufferInfo(); // temporary
     548
     549   defineModelGroupAttrib(modelGroups[ObjectType::LASER], "vertex_position", AttribType::POINT_VARYING,
    544550      3, GL_FLOAT, offset_of(&SceneObject::points));
    545    defineModelGroupAttrib(modelGroups[TYPE_LASER], "vt", ATTRIB_POINT_VARYING,
     551   defineModelGroupAttrib(modelGroups[ObjectType::LASER], "vt", AttribType::POINT_VARYING,
    546552      2, GL_FLOAT, offset_of(&SceneObject::texcoords));
    547    defineModelGroupAttrib(modelGroups[TYPE_LASER], "ubo_index", ATTRIB_OBJECT_VARYING,
     553   defineModelGroupAttrib(modelGroups[ObjectType::LASER], "ubo_index", AttribType::OBJECT_VARYING,
    548554      1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset));
    549555
    550    defineModelGroupUniform(modelGroups[TYPE_LASER], "view", ATTRIB_UNIFORM,
     556   defineModelGroupUniform(modelGroups[ObjectType::LASER], "view", AttribType::UNIFORM,
    551557      1, UNIFORM_MATRIX_4F, value_ptr(view_mat));
    552    defineModelGroupUniform(modelGroups[TYPE_LASER], "proj", ATTRIB_UNIFORM,
     558   defineModelGroupUniform(modelGroups[ObjectType::LASER], "proj", AttribType::UNIFORM,
    553559      1, UNIFORM_MATRIX_4F, value_ptr(proj_mat));
    554     defineModelGroupUniform(modelGroups[TYPE_LASER], "laser_color", ATTRIB_UNIFORM,
     560    defineModelGroupUniform(modelGroups[ObjectType::LASER], "laser_color", AttribType::UNIFORM,
    555561      1, UNIFORM_3F, laserColor);
    556562
    557    initModelGroupAttribs(modelGroups[TYPE_LASER]);
    558 
    559    modelGroups[TYPE_EXPLOSION] = createModelGroup(
     563   initModelGroupAttribs(modelGroups[ObjectType::LASER]);
     564
     565   modelGroups[ObjectType::EXPLOSION] = createModelGroup(
    560566      loadShaderProgram("gl-shaders/explosion.vert", "gl-shaders/explosion.frag"));
    561    shaderBufferInfo[modelGroups[TYPE_EXPLOSION].shaderProgram] = BufferInfo(); // temporary
    562 
    563    defineModelGroupAttrib(modelGroups[TYPE_EXPLOSION], "v_i", ATTRIB_POINT_VARYING,
     567   shaderBufferInfo[modelGroups[ObjectType::EXPLOSION].shaderProgram] = BufferInfo(); // temporary
     568
     569   defineModelGroupAttrib(modelGroups[ObjectType::EXPLOSION], "v_i", AttribType::POINT_VARYING,
    564570      3, GL_FLOAT, offset_of(&ParticleEffect::particleVelocities));
    565    defineModelGroupAttrib(modelGroups[TYPE_EXPLOSION], "start_time", ATTRIB_POINT_VARYING,
     571   defineModelGroupAttrib(modelGroups[ObjectType::EXPLOSION], "start_time", AttribType::POINT_VARYING,
    566572      1, GL_FLOAT, offset_of(&ParticleEffect::particleTimes));
    567    defineModelGroupAttrib(modelGroups[TYPE_EXPLOSION], "ubo_index", ATTRIB_OBJECT_VARYING,
     573   defineModelGroupAttrib(modelGroups[ObjectType::EXPLOSION], "ubo_index", AttribType::OBJECT_VARYING,
    568574      1, GL_UNSIGNED_INT, offset_of(&SceneObject::ubo_offset));
    569575
    570    defineModelGroupUniform(modelGroups[TYPE_EXPLOSION], "cur_time", ATTRIB_UNIFORM,
     576   defineModelGroupUniform(modelGroups[ObjectType::EXPLOSION], "cur_time", AttribType::UNIFORM,
    571577      1, UNIFORM_1F, &curTime);
    572    defineModelGroupUniform(modelGroups[TYPE_EXPLOSION], "view", ATTRIB_UNIFORM,
     578   defineModelGroupUniform(modelGroups[ObjectType::EXPLOSION], "view", AttribType::UNIFORM,
    573579      1, UNIFORM_MATRIX_4F, value_ptr(view_mat));
    574    defineModelGroupUniform(modelGroups[TYPE_EXPLOSION], "proj", ATTRIB_UNIFORM,
     580   defineModelGroupUniform(modelGroups[ObjectType::EXPLOSION], "proj", AttribType::UNIFORM,
    575581      1, UNIFORM_MATRIX_4F, value_ptr(proj_mat));
    576582
    577    initModelGroupAttribs(modelGroups[TYPE_EXPLOSION]);
     583   initModelGroupAttribs(modelGroups[ObjectType::EXPLOSION]);
    578584
    579585   cam_pos = vec3(0.0f, 0.0f, 2.0f);
     
    587593
    588594   float cam_speed = 1.0f;
    589    float cam_yaw_speed = 60.0f*ONE_DEG_IN_RAD;
    590    float cam_pitch_speed = 60.0f*ONE_DEG_IN_RAD;
     595   float cam_yaw_speed = radians(60.0f);
     596   float cam_pitch_speed = radians(60.0f);
    591597
    592598   // glm::lookAt can create the view matrix
     
    601607   // TODO: Create a function to construct the projection matrix
    602608   // (Maybe I should just use glm::perspective, after making sure it matches what I have now)
    603    float fov = 67.0f * ONE_DEG_IN_RAD;
     609   float fov = radians(67.0f);
    604610   float aspect = (float)windowWidth / (float)windowHeight;
    605611
     
    657663   GLuint ub_binding_point = 0;
    658664
    659    GLuint ship_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[TYPE_SHIP].shaderProgram, "models");
    660 
    661    GLuint asteroid_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[TYPE_ASTEROID].shaderProgram, "models");
    662 
    663    GLuint laser_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[TYPE_LASER].shaderProgram, "models");
    664 
    665    GLuint explosion_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[TYPE_EXPLOSION].shaderProgram, "models");
    666 
    667 
    668    glUseProgram(modelGroups[TYPE_SHIP].shaderProgram);
    669    bindUniformData(modelGroups[TYPE_SHIP].attribs["view"]);
    670    bindUniformData(modelGroups[TYPE_SHIP].attribs["proj"]);
    671 
    672    glUniformBlockBinding(modelGroups[TYPE_SHIP].shaderProgram, ship_sp_models_ub_index, ub_binding_point);
     665   GLuint ship_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ObjectType::SHIP].shaderProgram, "models");
     666
     667   GLuint asteroid_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ObjectType::ASTEROID].shaderProgram, "models");
     668
     669   GLuint laser_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ObjectType::LASER].shaderProgram, "models");
     670
     671   GLuint explosion_sp_models_ub_index = glGetUniformBlockIndex(modelGroups[ObjectType::EXPLOSION].shaderProgram, "models");
     672
     673
     674   glUseProgram(modelGroups[ObjectType::SHIP].shaderProgram);
     675   bindUniformData(modelGroups[ObjectType::SHIP].attribs["view"]);
     676   bindUniformData(modelGroups[ObjectType::SHIP].attribs["proj"]);
     677
     678   glUniformBlockBinding(modelGroups[ObjectType::SHIP].shaderProgram, ship_sp_models_ub_index, ub_binding_point);
    673679   glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
    674680
    675681
    676    glUseProgram(modelGroups[TYPE_ASTEROID].shaderProgram);
    677    bindUniformData(modelGroups[TYPE_ASTEROID].attribs["view"]);
    678    bindUniformData(modelGroups[TYPE_ASTEROID].attribs["proj"]);
    679 
    680    glUniformBlockBinding(modelGroups[TYPE_ASTEROID].shaderProgram, asteroid_sp_models_ub_index, ub_binding_point);
     682   glUseProgram(modelGroups[ObjectType::ASTEROID].shaderProgram);
     683   bindUniformData(modelGroups[ObjectType::ASTEROID].attribs["view"]);
     684   bindUniformData(modelGroups[ObjectType::ASTEROID].attribs["proj"]);
     685
     686   glUniformBlockBinding(modelGroups[ObjectType::ASTEROID].shaderProgram, asteroid_sp_models_ub_index, ub_binding_point);
    681687   glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
    682688
     
    685691   // Right now, I think I'm getting away without getting that uniform location because I'm only
    686692   // using one texture, so setting it to GL_TEXTURE0 once works
    687    glUseProgram(modelGroups[TYPE_LASER].shaderProgram);
    688    bindUniformData(modelGroups[TYPE_LASER].attribs["view"]);
    689    bindUniformData(modelGroups[TYPE_LASER].attribs["proj"]);
    690    bindUniformData(modelGroups[TYPE_LASER].attribs["laser_color"]);
    691 
    692    glUniformBlockBinding(modelGroups[TYPE_LASER].shaderProgram, laser_sp_models_ub_index, ub_binding_point);
     693   glUseProgram(modelGroups[ObjectType::LASER].shaderProgram);
     694   bindUniformData(modelGroups[ObjectType::LASER].attribs["view"]);
     695   bindUniformData(modelGroups[ObjectType::LASER].attribs["proj"]);
     696   bindUniformData(modelGroups[ObjectType::LASER].attribs["laser_color"]);
     697
     698   glUniformBlockBinding(modelGroups[ObjectType::LASER].shaderProgram, laser_sp_models_ub_index, ub_binding_point);
    693699   glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
    694700
    695701
    696    glUseProgram(modelGroups[TYPE_EXPLOSION].shaderProgram);
    697    bindUniformData(modelGroups[TYPE_EXPLOSION].attribs["view"]);
    698    bindUniformData(modelGroups[TYPE_EXPLOSION].attribs["proj"]);
    699 
    700    glUniformBlockBinding(modelGroups[TYPE_EXPLOSION].shaderProgram, explosion_sp_models_ub_index, ub_binding_point);
     702   glUseProgram(modelGroups[ObjectType::EXPLOSION].shaderProgram);
     703   bindUniformData(modelGroups[ObjectType::EXPLOSION].attribs["view"]);
     704   bindUniformData(modelGroups[ObjectType::EXPLOSION].attribs["proj"]);
     705
     706   glUniformBlockBinding(modelGroups[ObjectType::EXPLOSION].shaderProgram, explosion_sp_models_ub_index, ub_binding_point);
    701707   glBindBufferRange(GL_UNIFORM_BUFFER, ub_binding_point, ubo, 0, GL_MAX_UNIFORM_BLOCK_SIZE);
    702708/*** END OF REFACTORED CODE ***/
     
    720726   //glfwSwapInterval(0);
    721727
    722    State curState = STATE_MAIN_MENU;
     728   State curState = State::MAIN_MENU;
    723729
    724730   initGuiValueLists(valueLists);
     
    762768      while (!events.empty()) {
    763769         switch (events.front()) {
    764             case EVENT_GO_TO_MAIN_MENU:
    765                curState = STATE_MAIN_MENU;
     770         case Event::GO_TO_MAIN_MENU:
     771               curState = State::MAIN_MENU;
    766772               break;
    767             case EVENT_GO_TO_GAME:
    768                curState = STATE_GAME;
     773            case Event::GO_TO_GAME:
     774               curState = State::GAME;
    769775               break;
    770             case EVENT_QUIT:
     776            case Event::QUIT:
    771777               isRunning = false;
    772778               break;
     
    775781      }
    776782
    777       if (curState == STATE_GAME) {
     783      if (curState == State::GAME) {
    778784
    779785/*** START OF REFACTORED CODE ***/
     
    857863         for (unsigned int i = 0; i < objects.size(); i++) {
    858864            if (!objects[i]->deleted) {
    859                if (objects[i]->type == TYPE_ASTEROID) {
     865               if (objects[i]->type == ObjectType::ASTEROID) {
    860866                  transformObject(*objects[i], translate(mat4(1.0f), vec3(0.0f, 0.0f, 0.04f)), ubo);
    861867
     
    878884                     addObjectToScene(createExplosion(model_mat), shaderBufferInfo, modelGroups, ubo);
    879885                  }
    880                } else if (objects[i]->type == TYPE_EXPLOSION) {
     886               } else if (objects[i]->type == ObjectType::EXPLOSION) {
    881887                  ParticleEffect* explosion = (ParticleEffect*)objects[i];
    882888                  if (glfwGetTime() >= explosion->startTime + explosion->duration) {
     
    888894
    889895         if (leftLaser != NULL && !leftLaser->deleted) {
    890             updateLaserTarget(leftLaser, objects, modelGroups[TYPE_LASER], modelGroups[TYPE_ASTEROID].shaderProgram);
     896            updateLaserTarget(leftLaser, objects, modelGroups[ObjectType::LASER], modelGroups[ObjectType::ASTEROID].shaderProgram);
    891897         }
    892898         if (rightLaser != NULL && !rightLaser->deleted) {
    893             updateLaserTarget(rightLaser, objects, modelGroups[TYPE_LASER], modelGroups[TYPE_ASTEROID].shaderProgram);
     899            updateLaserTarget(rightLaser, objects, modelGroups[ObjectType::LASER], modelGroups[ObjectType::ASTEROID].shaderProgram);
    894900         }
    895901      }
     
    963969         view_mat = R * T;
    964970
    965          glUseProgram(modelGroups[TYPE_SHIP].shaderProgram);
    966          bindUniformData(modelGroups[TYPE_SHIP].attribs["view"]);
    967 
    968          glUseProgram(modelGroups[TYPE_LASER].shaderProgram);
    969          bindUniformData(modelGroups[TYPE_LASER].attribs["view"]);
     971         glUseProgram(modelGroups[ObjectType::SHIP].shaderProgram);
     972         bindUniformData(modelGroups[ObjectType::SHIP].attribs["view"]);
     973
     974         glUseProgram(modelGroups[ObjectType::LASER].shaderProgram);
     975         bindUniformData(modelGroups[ObjectType::LASER].attribs["view"]);
    970976
    971977         cam_moved = false;
    972978      }
    973979
    974       glUseProgram(modelGroups[TYPE_EXPLOSION].shaderProgram);
    975       bindUniformData(modelGroups[TYPE_EXPLOSION].attribs["cur_time"]);
     980      glUseProgram(modelGroups[ObjectType::EXPLOSION].shaderProgram);
     981      bindUniformData(modelGroups[ObjectType::EXPLOSION].attribs["cur_time"]);
    976982
    977983      // Render scene
     
    981987
    982988      switch (curState) {
    983          case STATE_MAIN_MENU:
     989         case State::MAIN_MENU:
    984990            renderMainMenu();
    985991            renderMainMenuGui();
    986992            break;
    987          case STATE_GAME:
     993         case State::GAME:
    988994            renderScene(modelGroups, ubo);
    989995            renderSceneGui(valueLists);
     
    9941000   }
    9951001
    996    ImGui_ImplGlfwGL3_Shutdown();
     1002   ImGui_ImplOpenGL3_Shutdown();
     1003   ImGui_ImplGlfw_Shutdown();
    9971004   ImGui::DestroyContext();
    9981005
     
    10401047
    10411048      for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
    1042          if ((*it)->type == TYPE_LASER) continue;
     1049         if ((*it)->type == ObjectType::LASER) continue;
    10431050         for (unsigned int p_idx = 0; p_idx < (*it)->points.size(); p_idx += 9) {
    10441051            if (faceClicked(
     
    13421349   }
    13431350
    1344    if (obj->type == TYPE_SHIP || obj->type == TYPE_ASTEROID) {
     1351   if (obj->type == ObjectType::SHIP || obj->type == ObjectType::ASTEROID) {
    13451352      calculateObjectBoundingBox(obj);
    13461353
     
    14441451   SceneObject* ship = new SceneObject();
    14451452
    1446    ship->type = TYPE_SHIP;
     1453   ship->type = ObjectType::SHIP;
    14471454
    14481455   ship->points = {
     
    18391846Laser* createLaser(vec3 start, vec3 end, vec3 color, GLfloat width) {
    18401847   Laser* obj = new Laser();
    1841    obj->type = TYPE_LASER;
     1848   obj->type = ObjectType::LASER;
    18421849   obj->targetAsteroid = NULL;
    18431850
     
    19701977   map<string, AttribInfo>::iterator it;
    19711978   for (it = modelGroup.attribs.begin(); it != modelGroup.attribs.end(); it++) {
    1972       if (it->second.attribType == ATTRIB_UNIFORM) {
     1979      if (it->second.attribType == AttribType::UNIFORM) {
    19731980         it->second.buffer = glGetUniformLocation(modelGroup.shaderProgram, it->first.c_str());
    19741981      } else {
     
    21332140      map<string, AttribInfo>::iterator attrIt;
    21342141      for (attrIt = smg->attribs.begin(); attrIt != smg->attribs.end(); attrIt++) {
    2135          if (attrIt->second.attribType != ATTRIB_UNIFORM) {
     2142         if (attrIt->second.attribType != AttribType::UNIFORM) {
    21362143            glBindBuffer(GL_ARRAY_BUFFER, attrIt->second.buffer);
    21372144            glBufferData(GL_ARRAY_BUFFER, smg->vboCapacity * GLsizeof(attrIt->second.type) * attrIt->second.size, NULL, GL_DYNAMIC_DRAW);
     
    21652172
    21662173      switch (it->second.attribType) {
    2167          case ATTRIB_POINT_VARYING:
     2174         case AttribType::POINT_VARYING:
    21682175            glBufferSubData(GL_ARRAY_BUFFER, obj.vertex_vbo_offset * GLsizeof(it->second.type) * it->second.size,
    21692176               obj.num_points * GLsizeof(it->second.type) * it->second.size, getVectorAttribPtr(obj, it->second.fieldOffset));
    21702177            break;
    2171          case ATTRIB_OBJECT_VARYING:
     2178         case AttribType::OBJECT_VARYING:
    21722179            for (unsigned int i = 0; i < obj.num_points; i++) {
    21732180               glBufferSubData(GL_ARRAY_BUFFER, (obj.vertex_vbo_offset + i) * GLsizeof(it->second.type) * it->second.size,
     
    21752182            }
    21762183            break;
    2177          case ATTRIB_UNIFORM:
     2184         case AttribType::UNIFORM:
    21782185            break;
    21792186      }
     
    21852192   glBufferSubData(GL_UNIFORM_BUFFER, obj.ubo_offset * sizeof(mat4), sizeof(mat4), value_ptr(obj.model_mat));
    21862193
    2187    if (obj.type == TYPE_ASTEROID) {
    2188       glUseProgram(modelGroups[TYPE_ASTEROID].shaderProgram);
     2194   if (obj.type == ObjectType::ASTEROID) {
     2195      glUseProgram(modelGroups[ObjectType::ASTEROID].shaderProgram);
    21892196
    21902197      ostringstream oss;
    21912198      oss << "hp[" << obj.ubo_offset << "]";
    2192       glUniform1f(glGetUniformLocation(modelGroups[TYPE_ASTEROID].shaderProgram, oss.str().c_str()), ((Asteroid&)obj).hp);
    2193    } else if (obj.type == TYPE_EXPLOSION) {
    2194       glUseProgram(modelGroups[TYPE_EXPLOSION].shaderProgram);
     2199      glUniform1f(glGetUniformLocation(modelGroups[ObjectType::ASTEROID].shaderProgram, oss.str().c_str()), ((Asteroid&)obj).hp);
     2200   } else if (obj.type == ObjectType::EXPLOSION) {
     2201      glUseProgram(modelGroups[ObjectType::EXPLOSION].shaderProgram);
    21952202
    21962203      ostringstream oss;
    21972204      oss << "explosion_start_time[" << obj.ubo_offset << "]";
    2198       glUniform1f(glGetUniformLocation(modelGroups[TYPE_EXPLOSION].shaderProgram, oss.str().c_str()), ((ParticleEffect&)obj).startTime);
     2205      glUniform1f(glGetUniformLocation(modelGroups[ObjectType::EXPLOSION].shaderProgram, oss.str().c_str()), ((ParticleEffect&)obj).startTime);
    21992206   }
    22002207
     
    22552262
    22562263   for (vector<SceneObject*>::iterator it = objects.begin(); it != objects.end(); it++) {
    2257       if ((*it)->type == TYPE_ASTEROID && !(*it)->deleted && getLaserAndAsteroidIntersection(start, end, **it, intersection)) {
     2264      if ((*it)->type == ObjectType::ASTEROID && !(*it)->deleted && getLaserAndAsteroidIntersection(start, end, **it, intersection)) {
    22582265         // TODO: Implement a more generic algorithm for testing the closest object by getting the distance between the points
    22592266         if (closestAsteroid == NULL || intersection.z > closestIntersection.z) {
     
    23672374void renderScene(map<ObjectType, ShaderModelGroup>& modelGroups, GLuint ubo) {
    23682375
    2369    glUseProgram(modelGroups[TYPE_SHIP].shaderProgram);
    2370    glBindVertexArray(modelGroups[TYPE_SHIP].vao);
    2371 
    2372    glDrawArrays(GL_TRIANGLES, 0, modelGroups[TYPE_SHIP].numPoints);
    2373 
    2374    glUseProgram(modelGroups[TYPE_ASTEROID].shaderProgram);
    2375    glBindVertexArray(modelGroups[TYPE_ASTEROID].vao);
    2376 
    2377    glDrawArrays(GL_TRIANGLES, 0, modelGroups[TYPE_ASTEROID].numPoints);
     2376   glUseProgram(modelGroups[ObjectType::SHIP].shaderProgram);
     2377   glBindVertexArray(modelGroups[ObjectType::SHIP].vao);
     2378
     2379   glDrawArrays(GL_TRIANGLES, 0, modelGroups[ObjectType::SHIP].numPoints);
     2380
     2381   glUseProgram(modelGroups[ObjectType::ASTEROID].shaderProgram);
     2382   glBindVertexArray(modelGroups[ObjectType::ASTEROID].vao);
     2383
     2384   glDrawArrays(GL_TRIANGLES, 0, modelGroups[ObjectType::ASTEROID].numPoints);
    23782385
    23792386   glEnable(GL_BLEND);
    23802387
    2381    glUseProgram(modelGroups[TYPE_LASER].shaderProgram);
    2382    glBindVertexArray(modelGroups[TYPE_LASER].vao);
    2383 
    2384    glDrawArrays(GL_TRIANGLES, 0, modelGroups[TYPE_LASER].numPoints);
    2385 
    2386    glUseProgram(modelGroups[TYPE_EXPLOSION].shaderProgram);
    2387    glBindVertexArray(modelGroups[TYPE_EXPLOSION].vao);
     2388   glUseProgram(modelGroups[ObjectType::LASER].shaderProgram);
     2389   glBindVertexArray(modelGroups[ObjectType::LASER].vao);
     2390
     2391   glDrawArrays(GL_TRIANGLES, 0, modelGroups[ObjectType::LASER].numPoints);
     2392
     2393   glUseProgram(modelGroups[ObjectType::EXPLOSION].shaderProgram);
     2394   glBindVertexArray(modelGroups[ObjectType::EXPLOSION].vao);
    23882395
    23892396   glEnable(GL_PROGRAM_POINT_SIZE);
    23902397
    2391    glDrawArrays(GL_POINTS, 0, modelGroups[TYPE_EXPLOSION].numPoints);
     2398   glDrawArrays(GL_POINTS, 0, modelGroups[ObjectType::EXPLOSION].numPoints);
    23922399
    23932400   glDisable(GL_PROGRAM_POINT_SIZE);
     
    23972404
    23982405void renderSceneGui(map<string, vector<UIValue>> valueLists) {
    2399    ImGui_ImplGlfwGL3_NewFrame();
     2406   ImGui_ImplOpenGL3_NewFrame();
     2407   ImGui_ImplGlfw_NewFrame();
     2408   ImGui::NewFrame();
    24002409
    24012410   // 1. Show a simple window.
     
    24432452      ImGui::SameLine();
    24442453      if (ImGui::Button("Main Menu")) {
    2445          events.push(EVENT_GO_TO_MAIN_MENU);
     2454         events.push(Event::GO_TO_MAIN_MENU);
    24462455      }
    24472456      ImGui::End();
     
    24622471
    24632472   ImGui::Render();
    2464    ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
     2473   ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
    24652474}
    24662475
     
    24702479/*** START OF REFACTORED CODE ***/
    24712480void renderMainMenuGui() {
    2472    ImGui_ImplGlfwGL3_NewFrame();
     2481   ImGui_ImplOpenGL3_NewFrame();
     2482   ImGui_ImplGlfw_NewFrame();
     2483   ImGui::NewFrame();
    24732484
    24742485   {
     
    24852496      ImGui::SameLine();
    24862497      if (ImGui::Button("New Game")) {
    2487          events.push(EVENT_GO_TO_GAME);
     2498         events.push(Event::GO_TO_GAME);
    24882499      }
    24892500
     
    24922503      ImGui::SameLine();
    24932504      if (ImGui::Button("Quit")) {
    2494          events.push(EVENT_QUIT);
     2505         events.push(Event::QUIT);
    24952506      }
    24962507
     
    24992510
    25002511   ImGui::Render();
    2501    ImGui_ImplGlfwGL3_RenderDrawData(ImGui::GetDrawData());
     2512   ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
    25022513}
    25032514/*** END OF REFACTORED CODE ***/
     
    25442555Asteroid* createAsteroid(vec3 pos) {
    25452556   Asteroid* obj = new Asteroid();
    2546    obj->type = TYPE_ASTEROID;
     2557   obj->type = ObjectType::ASTEROID;
    25472558   obj->hp = 10.0f;
    25482559
     
    26482659
    26492660   mat4 T = translate(mat4(1.0f), pos);
    2650    mat4 R = rotate(mat4(1.0f), 60.0f * (float)ONE_DEG_IN_RAD, vec3(1.0f, 1.0f, -1.0f));
     2661   mat4 R = rotate(mat4(1.0f), radians(60.0f), vec3(1.0f, 1.0f, -1.0f));
    26512662   obj->model_base = T * R * scale(mat4(1.0f), vec3(0.1f, 0.1f, 0.1f));
    26522663
     
    26682679   ParticleEffect* obj = new ParticleEffect();
    26692680
    2670    obj->type = TYPE_EXPLOSION;
     2681   obj->type = ObjectType::EXPLOSION;
    26712682
    26722683   initObject(obj);
Note: See TracChangeset for help on using the changeset viewer.