Engine
Frameworkcreatedbymeusableforthecreationofsimplegames.CurrentlysupportsOpenGL(Verysimple)andVulkan.
imgui.cpp
Go to the documentation of this file.
1 // dear imgui, v1.52 WIP
2 // (main code and documentation)
3 
4 // See ImGui::ShowTestWindow() 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
9 // 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, e.g: https://www.patreon.com/imgui
12 
13 /*
14 
15  Index
16  - MISSION STATEMENT
17  - END-USER GUIDE
18  - PROGRAMMER GUIDE (read me!)
19  - Read first
20  - How to update to a newer version of Dear ImGui
21  - Getting started with integrating Dear ImGui in your code/engine
22  - API BREAKING CHANGES (read me when you update!)
23  - ISSUES & TODO LIST
24  - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
25  - How can I help?
26  - What is ImTextureID and how do I display an image?
27  - I integrated Dear ImGui in my engine and the text or lines are blurry..
28  - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
29  - How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on labels/IDs.
30  - How can I tell when Dear ImGui wants my mouse/keyboard inputs VS when I can pass them to my application?
31  - How can I load a different font than the default?
32  - How can I easily use icons in my application?
33  - How can I load multiple fonts?
34  - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
35  - How can I preserve my Dear ImGui context across reloading a DLL? (loss of the global/static variables)
36  - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
37  - ISSUES & TODO-LIST
38  - CODE
39 
40 
41  MISSION STATEMENT
42  =================
43 
44  - Easy to use to create code-driven and data-driven tools
45  - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools
46  - Easy to hack and improve
47  - Minimize screen real-estate usage
48  - Minimize setup and maintenance
49  - Minimize state storage on user side
50  - Portable, minimize dependencies, run on target (consoles, phones, etc.)
51  - Efficient runtime and memory consumption (NB- we do allocate when "growing" content - creating a window / opening a tree node for the first time, etc. - but a typical frame won't allocate anything)
52 
53  Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
54  - Doesn't look fancy, doesn't animate
55  - Limited layout features, intricate layouts are typically crafted in code
56 
57 
58  END-USER GUIDE
59  ==============
60 
61  - Double-click title bar to collapse window
62  - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin()
63  - Click and drag on lower right corner to resize window
64  - Click and drag on any empty space to move window
65  - Double-click/double-tap on lower right corner grip to auto-fit to content
66  - TAB/SHIFT+TAB to cycle through keyboard editable fields
67  - Use mouse wheel to scroll
68  - Use CTRL+mouse wheel to zoom window contents (if io.FontAllowScaling is true)
69  - CTRL+Click on a slider or drag box to input value as text
70  - Text editor:
71  - Hold SHIFT or use mouse to select text.
72  - CTRL+Left/Right to word jump
73  - CTRL+Shift+Left/Right to select words
74  - CTRL+A our Double-Click to select all
75  - CTRL+X,CTRL+C,CTRL+V to use OS clipboard
76  - CTRL+Z,CTRL+Y to undo/redo
77  - ESCAPE to revert text to its original value
78  - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
79  - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
80 
81 
82  PROGRAMMER GUIDE
83  ================
84 
85  READ FIRST
86 
87  - Read the FAQ below this section!
88  - Your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs.
89  - Call and read ImGui::ShowTestWindow() for demo code demonstrating most features.
90  - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861
91 
92  HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
93 
94  - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
95  - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
96  If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed from the public API.
97  If you have a problem with a missing function/symbols, search for its name in the code, there will likely be a comment about it.
98  Please report any issue to the GitHub page!
99  - Try to keep your copy of dear imgui reasonably up to date.
100 
101  GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
102 
103  - Add the Dear ImGui source files to your projects, using your preferred build system. It is recommended you build the .cpp files as part of your project and not as a library.
104  - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types.
105  - See examples/ folder for standalone sample applications. To understand the integration process, you can read examples/opengl2_example/ because it is short,
106  then switch to the one more appropriate to your use case.
107  - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/.
108  - When using Dear ImGui, your programming IDE if your friend: follow the declaration of variables, functions and types to find comments about them.
109 
110  - Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize (application resolution).
111  Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic integration you don't need to worry about it all.
112  - Init: call io.Fonts->GetTexDataAsRGBA32(...), it will build the font atlas texture, then load the texture pixels into graphics memory.
113  - Every frame:
114  - In your main loop as early a possible, fill the IO fields marked 'Input' (e.g. mouse position, buttons, keyboard info, etc.)
115  - Call ImGui::NewFrame() to begin the frame
116  - You can use any ImGui function you want between NewFrame() and Render()
117  - Call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your io.RenderDrawListFn handler.
118  (if you don't need to render, you still need to call Render() and ignore the callback, or call EndFrame() instead. if you call neither some aspects of windows focusing/moving will appear broken.)
119  - All rendering information are stored into command-lists until ImGui::Render() is called.
120  - Dear ImGui never touches or knows about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide.
121  - Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases of your own application.
122  - Refer to the examples applications in the examples/ folder for instruction on how to setup your code.
123  - A minimal application skeleton may be:
124 
125  // Application init
126  ImGuiIO& io = ImGui::GetIO();
127  io.DisplaySize.x = 1920.0f;
128  io.DisplaySize.y = 1280.0f;
129  io.RenderDrawListsFn = MyRenderFunction; // Setup a render function, or set to NULL and call GetDrawData() after Render() to access the render data.
130  // TODO: Fill others settings of the io structure later.
131 
132  // Load texture atlas (there is a default font so you don't need to care about choosing a font yet)
133  unsigned char* pixels;
134  int width, height;
135  io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height);
136  // TODO: At this points you've got the texture data and you need to upload that your your graphic system:
137  MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA)
138  // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'. This will be passed back to your via the renderer.
139  io.Fonts->TexID = (void*)texture;
140 
141  // Application main loop
142  while (true)
143  {
144  // Setup low-level inputs (e.g. on Win32, GetKeyboardState(), or write to those fields from your Windows message loop handlers, etc.)
145  ImGuiIO& io = ImGui::GetIO();
146  io.DeltaTime = 1.0f/60.0f;
147  io.MousePos = mouse_pos;
148  io.MouseDown[0] = mouse_button_0;
149  io.MouseDown[1] = mouse_button_1;
150 
151  // Call NewFrame(), after this point you can use ImGui::* functions anytime
152  ImGui::NewFrame();
153 
154  // Most of your application code here
155  MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
156  MyGameRender(); // may use any ImGui functions as well!
157 
158  // Render & swap video buffers
159  ImGui::Render();
160  SwapBuffers();
161  }
162 
163  - A minimal render function skeleton may be:
164 
165  void void MyRenderFunction(ImDrawData* draw_data)(ImDrawData* draw_data)
166  {
167  // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
168  // TODO: Setup viewport, orthographic projection matrix
169  // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
170  for (int n = 0; n < draw_data->CmdListsCount; n++)
171  {
172  const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui
173  const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui
174  for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
175  {
176  const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
177  if (pcmd->UserCallback)
178  {
179  pcmd->UserCallback(cmd_list, pcmd);
180  }
181  else
182  {
183  // Render 'pcmd->ElemCount/3' texture triangles
184  MyEngineBindTexture(pcmd->TextureId);
185  MyEngineScissor((int)pcmd->ClipRect.x, (int)pcmd->ClipRect.y, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
186  MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
187  }
188  idx_buffer += pcmd->ElemCount;
189  }
190  }
191  }
192 
193  - The examples/ folders contains many functional implementation of the pseudo-code above.
194  - When calling NewFrame(), the 'io.WantCaptureMouse'/'io.WantCaptureKeyboard'/'io.WantTextInput' flags are updated.
195  They tell you if ImGui intends to use your inputs. So for example, if 'io.WantCaptureMouse' is set you would typically want to hide
196  mouse inputs from the rest of your application. Read the FAQ below for more information about those flags.
197 
198 
199 
200  API BREAKING CHANGES
201  ====================
202 
203  Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
204  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.
205  Also read releases logs https://github.com/ocornut/imgui/releases for more details.
206 
207  - 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).
208  - 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)".
209  - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete).
210  - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
211  - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
212  - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
213  - 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.
214  - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame.
215  - 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.
216  - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete).
217  - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete).
218  - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
219  - 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.
220  - 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.
221  - 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))'
222  - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
223  - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
224  - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
225  - 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().
226  - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
227  - 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.
228  - 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.
229  - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
230  If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
231  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.
232  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.
233  ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col)
234  {
235  float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a;
236  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);
237  }
238  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.
239  - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
240  - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
241  - 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).
242  - 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.
243  - 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).
244  - 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)
245  - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
246  - 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.
247  - 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.
248  - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
249  - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
250  - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
251  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.
252  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!
253  - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
254  - 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.
255  - 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
256  - 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.
257  you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
258  - 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.
259  this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
260  - 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.
261  - the signature of the io.RenderDrawListsFn handler has changed!
262  ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
263  became:
264  ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
265  argument 'cmd_lists' -> 'draw_data->CmdLists'
266  argument 'cmd_lists_count' -> 'draw_data->CmdListsCount'
267  ImDrawList 'commands' -> 'CmdBuffer'
268  ImDrawList 'vtx_buffer' -> 'VtxBuffer'
269  ImDrawList n/a -> 'IdxBuffer' (new)
270  ImDrawCmd 'vtx_count' -> 'ElemCount'
271  ImDrawCmd 'clip_rect' -> 'ClipRect'
272  ImDrawCmd 'user_callback' -> 'UserCallback'
273  ImDrawCmd 'texture_id' -> 'TextureId'
274  - 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.
275  - 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!
276  - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
277  - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
278  - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
279  - 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.
280  - 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
281  - 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!
282  - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
283  - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
284  - 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.
285  - 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.
286  - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
287  - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
288  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
289  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
290  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
291  - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
292  - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
293  - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
294  - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
295  - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
296  - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
297  - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
298  - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
299  - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
300  - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
301  - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
302  - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
303  (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
304  this sequence:
305  const void* png_data;
306  unsigned int png_size;
307  ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
308  // <Copy to GPU>
309  became:
310  unsigned char* pixels;
311  int width, height;
312  io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
313  // <Copy to GPU>
314  io.Fonts->TexID = (your_texture_identifier);
315  you now have much more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
316  it is now recommended that you sample the font texture with bilinear interpolation.
317  (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
318  (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
319  (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
320  - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
321  - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
322  - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
323  - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
324  - 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)
325  - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
326  - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
327  - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
328  - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
329  - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
330  - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
331 
332 
333  ISSUES & TODO-LIST
334  ==================
335  See TODO.txt
336 
337 
338  FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
339  ======================================
340 
341  Q: How can I help?
342  A: - If you are experienced enough with Dear ImGui and with C/C++, look at the todo list and see how you want/can help!
343  - Become a Patron/donate! Convince your company to become a Patron or provide serious funding for development time! See http://www.patreon.com/imgui
344 
345  Q: What is ImTextureID and how do I display an image?
346  A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function.
347  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!
348  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.
349  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.
350  Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing.
351  (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!)
352  To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions.
353  Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use.
354  It is your responsibility to get textures uploaded to your GPU.
355 
356  Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
357  A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
358  Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
359 
360  Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
361  A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
362 
363  Q: Can I have multiple widgets with the same label? Can I have widget without a label?
364  A: Yes. A primer on the use of labels/IDs in Dear ImGui..
365 
366  - Elements that are not clickable, such as Text() items don't need an ID.
367 
368  - Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui often needs to remember what is the "active" widget).
369  to do so they need a unique ID. unique ID are typically derived from a string label, an integer index or a pointer.
370 
371  Button("OK"); // Label = "OK", ID = hash of "OK"
372  Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel"
373 
374  - ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK" in two different windows
375  or in two different locations of a tree.
376 
377  - If you have a same ID twice in the same location, you'll have a conflict:
378 
379  Button("OK");
380  Button("OK"); // ID collision! Both buttons will be treated as the same.
381 
382  Fear not! this is easy to solve and there are many ways to solve it!
383 
384  - When passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases.
385  use "##" to pass a complement to the ID that won't be visible to the end-user:
386 
387  Button("Play"); // Label = "Play", ID = hash of "Play"
388  Button("Play##foo1"); // Label = "Play", ID = hash of "Play##foo1" (different from above)
389  Button("Play##foo2"); // Label = "Play", ID = hash of "Play##foo2" (different from above)
390 
391  - If you want to completely hide the label, but still need an ID:
392 
393  Checkbox("##On", &b); // Label = "", ID = hash of "##On" (no label!)
394 
395  - Occasionally/rarely you might want change a label while preserving a constant ID. This allows you to animate labels.
396  For example you may want to include varying information in a window title bar (and windows are uniquely identified by their ID.. obviously)
397  Use "###" to pass a label that isn't part of ID:
398 
399  Button("Hello###ID"; // Label = "Hello", ID = hash of "ID"
400  Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above)
401 
402  sprintf(buf, "My game (%f FPS)###MyGame");
403  Begin(buf); // Variable label, ID = hash of "MyGame"
404 
405  - Use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window.
406  This is the most convenient way of distinguishing ID if you are iterating and creating many UI elements.
407  You can push a pointer, a string or an integer value. Remember that ID are formed from the concatenation of everything in the ID stack!
408 
409  for (int i = 0; i < 100; i++)
410  {
411  PushID(i);
412  Button("Click"); // Label = "Click", ID = hash of integer + "label" (unique)
413  PopID();
414  }
415 
416  for (int i = 0; i < 100; i++)
417  {
418  MyObject* obj = Objects[i];
419  PushID(obj);
420  Button("Click"); // Label = "Click", ID = hash of pointer + "label" (unique)
421  PopID();
422  }
423 
424  for (int i = 0; i < 100; i++)
425  {
426  MyObject* obj = Objects[i];
427  PushID(obj->Name);
428  Button("Click"); // Label = "Click", ID = hash of string + "label" (unique)
429  PopID();
430  }
431 
432  - More example showing that you can stack multiple prefixes into the ID stack:
433 
434  Button("Click"); // Label = "Click", ID = hash of "Click"
435  PushID("node");
436  Button("Click"); // Label = "Click", ID = hash of "node" + "Click"
437  PushID(my_ptr);
438  Button("Click"); // Label = "Click", ID = hash of "node" + ptr + "Click"
439  PopID();
440  PopID();
441 
442  - Tree nodes implicitly creates a scope for you by calling PushID().
443 
444  Button("Click"); // Label = "Click", ID = hash of "Click"
445  if (TreeNode("node"))
446  {
447  Button("Click"); // Label = "Click", ID = hash of "node" + "Click"
448  TreePop();
449  }
450 
451  - When working with trees, ID are used to preserve the open/close state of each tree node.
452  Depending on your use cases you may want to use strings, indices or pointers as ID.
453  e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change.
454  e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense!
455 
456  Q: How can I tell when Dear ImGui wants my mouse/keyboard inputs VS when I can pass them to my application?
457  A: You can read the 'io.WantCaptureMouse'/'io.WantCaptureKeyboard'/'ioWantTextInput' flags from the ImGuiIO structure.
458  - When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application.
459  - 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 without a keyboard).
460  Preferably read the flags after calling ImGui::NewFrame() to avoid them lagging by one frame. But reading those flags before calling NewFrame() is also generally ok,
461  as the bool toggles fairly rarely and you don't generally expect to interact with either Dear ImGui or your application during the same frame when that transition occurs.
462  Dear ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, so 'io.WantCaptureMouse' is more accurate and correct than checking if a window is hovered.
463  (Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically have 'io.WantCaptureKeyboard=false'.
464  Depending on your application logic it may or not be inconvenient. You might want to track which key-downs were for Dear ImGui (e.g. with an array of bool) and filter out the corresponding key-ups.)
465 
466  Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13)
467  A: Use the font atlas to load the TTF/OTF file you want:
468 
469  ImGuiIO& io = ImGui::GetIO();
470  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
471  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
472 
473  Q: How can I easily use icons in my application?
474  A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you main font. Then you can refer to icons within your strings.
475  Read 'How can I load multiple fonts?' and the file 'extra_fonts/README.txt' for instructions.
476 
477  Q: How can I load multiple fonts?
478  A: Use the font atlas to pack them into a single texture:
479  (Read extra_fonts/README.txt and the code in ImFontAtlas for more details.)
480 
481  ImGuiIO& io = ImGui::GetIO();
482  ImFont* font0 = io.Fonts->AddFontDefault();
483  ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
484  ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
485  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
486  // the first loaded font gets used by default
487  // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
488 
489  // Options
490  ImFontConfig config;
491  config.OversampleH = 3;
492  config.OversampleV = 1;
493  config.GlyphOffset.y -= 2.0f; // Move everything by 2 pixels up
494  config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters
495  io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config);
496 
497  // Combine multiple fonts into one (e.g. for icon fonts)
498  ImWchar ranges[] = { 0xf000, 0xf3ff, 0 };
499  ImFontConfig config;
500  config.MergeMode = true;
501  io.Fonts->AddFontDefault();
502  io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font
503  io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs
504 
505  Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
506  A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
507 
508  // Add default Japanese ranges
509  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
510 
511  // 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)
512  ImVector<ImWchar> ranges;
513  ImFontAtlas::GlyphRangesBuilder builder;
514  builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
515  builder.AddChar(0x7262); // Add a specific character
516  builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
517  builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted)
518  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
519 
520  All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax.
521  Specifying literal in your source code using a local code page (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
522  Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
523 
524  Text input: it is up to your application to pass the right character code to io.AddInputCharacter(). The applications in examples/ are doing that.
525  For languages using IME, on Windows you can copy the Hwnd of your application to io.ImeWindowHandle. The default implementation of io.ImeSetInputScreenPosFn() on Windows will set your IME position correctly.
526 
527  Q: How can I preserve my Dear ImGui context across reloading a DLL? (loss of the global/static variables)
528  A: Create your own context 'ctx = CreateContext()' + 'SetCurrentContext(ctx)' and your own font atlas 'ctx->GetIO().Fonts = new ImFontAtlas()' so you don't rely on the default globals.
529 
530  Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
531  A: The easiest way is to create a dummy window. Call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flag, zero background alpha,
532  then retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
533  You can also perfectly create a standalone ImDrawList instance _but_ you need ImGui to be initialized because ImDrawList pulls from ImGui data to retrieve the coordinates of the white pixel.
534 
535  - tip: the construct 'IMGUI_ONCE_UPON_A_FRAME { ... }' will run the block of code only once a frame. You can use it to quickly add custom UI in the middle of a deep nested inner loop in your code.
536  - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug"
537  - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. this is also useful to set yourself in the context of another window (to get/set other settings)
538  - tip: you can call Render() multiple times (e.g for VR renders).
539  - tip: call and read the ShowTestWindow() code in imgui_demo.cpp for more example of how to use ImGui!
540 
541 */
542 
543 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
544 #define _CRT_SECURE_NO_WARNINGS
545 #endif
546 
547 #include "imgui.h"
548 #define IMGUI_DEFINE_MATH_OPERATORS
549 #define IMGUI_DEFINE_PLACEMENT_NEW
550 #include "imgui_internal.h"
551 
552 #include <ctype.h> // toupper, isprint
553 #include <stdlib.h> // NULL, malloc, free, qsort, atoi
554 #include <stdio.h> // vsnprintf, sscanf, printf
555 #include <limits.h> // INT_MIN, INT_MAX
556 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
557 #include <stddef.h> // intptr_t
558 #else
559 #include <stdint.h> // intptr_t
560 #endif
561 
562 #ifdef _MSC_VER
563 #pragma warning (disable: 4127) // condition expression is constant
564 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
565 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
566 #endif
567 
568 // Clang warnings with -Weverything
569 #ifdef __clang__
570 #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!
571 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
572 #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.
573 #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.
574 #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.
575 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
576 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
577 #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.
578 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' //
579 #elif defined(__GNUC__)
580 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
581 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
582 #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
583 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
584 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
585 #pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'xxxx' to type 'xxxx' casts away qualifiers
586 #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
587 #endif
588 
589 //-------------------------------------------------------------------------
590 // Forward Declarations
591 //-------------------------------------------------------------------------
592 
593 static float GetDraggedColumnOffset(int column_index);
594 
595 static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
596 
597 static ImFont* GetDefaultFont();
598 static void SetCurrentFont(ImFont* font);
599 static void SetCurrentWindow(ImGuiWindow* window);
600 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
601 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond);
602 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond);
603 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond);
604 static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs);
605 static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags);
606 static void ClearSetNextWindowData();
607 static void CheckStacksSize(ImGuiWindow* window, bool write);
608 static void Scrollbar(ImGuiWindow* window, bool horizontal);
609 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);
610 
611 static void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_list, ImDrawList* draw_list);
612 static void AddWindowToRenderList(ImVector<ImDrawList*>& out_render_list, ImGuiWindow* window);
613 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>& out_sorted_windows, ImGuiWindow* window);
614 
615 static ImGuiIniData* FindWindowSettings(const char* name);
616 static ImGuiIniData* AddWindowSettings(const char* name);
617 static void LoadIniSettingsFromDisk(const char* ini_filename);
618 static void SaveIniSettingsToDisk(const char* ini_filename);
619 static void MarkIniSettingsDirty(ImGuiWindow* window);
620 
621 static ImRect GetVisibleRect();
622 
623 static void CloseInactivePopups();
624 static void ClosePopupToLevel(int remaining);
625 static ImGuiWindow* GetFrontMostModalRootWindow();
626 static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& rect_to_avoid);
627 
628 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data);
629 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
630 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);
631 
632 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size);
633 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size);
634 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const void* value2);
635 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format);
636 
637 //-----------------------------------------------------------------------------
638 // Platform dependent default implementations
639 //-----------------------------------------------------------------------------
640 
641 static const char* GetClipboardTextFn_DefaultImpl(void* user_data);
642 static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
643 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
644 
645 //-----------------------------------------------------------------------------
646 // Context
647 //-----------------------------------------------------------------------------
648 
649 // Default font atlas storage.
650 // New contexts always point by default to this font atlas. It can be changed by reassigning the GetIO().Fonts variable.
651 static ImFontAtlas GImDefaultFontAtlas;
652 
653 // Default context storage + current context pointer.
654 // Implicitely used by all ImGui functions. Always assumed to be != NULL. Change to a different context by calling ImGui::SetCurrentContext()
655 // If you are hot-reloading this code in a DLL you will lose the static/global variables. Create your own context+font atlas instead of relying on those default (see FAQ entry "How can I preserve my ImGui context across reloading a DLL?").
656 // ImGui is currently not thread-safe because of this variable. If you want thread-safety to allow N threads to access N different contexts, you might work around it by:
657 // - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts)
658 // - or: Changing this variable to be TLS. You may #define GImGui in imconfig.h for further custom hackery. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
659 #ifndef GImGui
660 static ImGuiContext GImDefaultContext;
661 ImGuiContext* GImGui = &GImDefaultContext;
662 #endif
663 
664 //-----------------------------------------------------------------------------
665 // User facing structures
666 //-----------------------------------------------------------------------------
667 
669 {
670  Alpha = 1.0f; // Global alpha applies to everything in ImGui
671  WindowPadding = ImVec2(8,8); // Padding within a window
672  WindowMinSize = ImVec2(32,32); // Minimum window size
673  WindowRounding = 9.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows
674  WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
675  ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
676  FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
677  FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
678  ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
679  ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
680  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!
681  IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
682  ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
683  ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
684  ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
685  GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
686  GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
687  ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
688  DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
689  DisplaySafeAreaPadding = ImVec2(4,4); // 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.
690  AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
691  AntiAliasedShapes = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
692  CurveTessellationTol = 1.25f; // Tessellation tolerance. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
693 
695 }
696 
698 {
699  ImGuiStyle* style = dst ? dst : &ImGui::GetStyle();
700  ImVec4* colors = style->Colors;
701 
702  colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
703  colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
704  colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f);
705  colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
706  colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f);
707  colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 0.40f);
708  colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
709  colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input
710  colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f);
711  colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f);
712  colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
713  colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
714  colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
715  colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
716  colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
717  colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
718  colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
719  colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 0.40f);
720  colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f);
721  colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
722  colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
723  colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f);
724  colors[ImGuiCol_Button] = ImVec4(0.67f, 0.40f, 0.40f, 0.60f);
725  colors[ImGuiCol_ButtonHovered] = ImVec4(0.67f, 0.40f, 0.40f, 1.00f);
726  colors[ImGuiCol_ButtonActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f);
727  colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
728  colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
729  colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
730  colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
731  colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
732  colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
733  colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
734  colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f);
735  colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f);
736  colors[ImGuiCol_CloseButton] = ImVec4(0.50f, 0.50f, 0.90f, 0.50f);
737  colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.70f, 0.70f, 0.90f, 0.60f);
738  colors[ImGuiCol_CloseButtonActive] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
739  colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
740  colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
741  colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
742  colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
743  colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
744  colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
745 }
746 
748 {
749  // Most fields are initialized with zero
750  memset(this, 0, sizeof(*this));
751 
752  // Settings
753  DisplaySize = ImVec2(-1.0f, -1.0f);
754  DeltaTime = 1.0f/60.0f;
755  IniSavingRate = 5.0f;
756  IniFilename = "imgui.ini";
757  LogFilename = "imgui_log.txt";
758  MouseDoubleClickTime = 0.30f;
759  MouseDoubleClickMaxDist = 6.0f;
760  for (int i = 0; i < ImGuiKey_COUNT; i++)
761  KeyMap[i] = -1;
762  KeyRepeatDelay = 0.250f;
763  KeyRepeatRate = 0.050f;
764  UserData = NULL;
765 
766  Fonts = &GImDefaultFontAtlas;
767  FontGlobalScale = 1.0f;
768  FontDefault = NULL;
769  FontAllowUserScaling = false;
770  DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
771  DisplayVisibleMin = DisplayVisibleMax = ImVec2(0.0f, 0.0f);
772 
773  // User functions
774  RenderDrawListsFn = NULL;
775  MemAllocFn = malloc;
776  MemFreeFn = free;
777  GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
778  SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
779  ClipboardUserData = NULL;
780  ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
781  ImeWindowHandle = NULL;
782 
783  // Input (NB: we already have memset zero the entire structure)
784  MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
785  MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
786  MouseDragThreshold = 6.0f;
787  for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
788  for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f;
789 
790  // Set OS X style defaults based on __APPLE__ Compile time flag
791 #ifdef __APPLE__
792  OSXBehaviors = true;
793 #endif
794 }
795 
796 // Pass in translated ASCII characters for text input.
797 // - with glfw you can get those from the callback set in glfwSetCharCallback()
798 // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
800 {
801  const int n = ImStrlenW(InputCharacters);
802  if (n + 1 < IM_ARRAYSIZE(InputCharacters))
803  {
804  InputCharacters[n] = c;
805  InputCharacters[n+1] = '\0';
806  }
807 }
808 
809 void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
810 {
811  // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more
812  const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar);
813  ImWchar wchars[wchars_buf_len];
814  ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL);
815  for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++)
816  AddInputCharacter(wchars[i]);
817 }
818 
819 //-----------------------------------------------------------------------------
820 // HELPERS
821 //-----------------------------------------------------------------------------
822 
823 #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
824 #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
825 
826 // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n.
827 #ifdef _WIN32
828 #define IM_NEWLINE "\r\n"
829 #else
830 #define IM_NEWLINE "\n"
831 #endif
832 
833 ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
834 {
835  ImVec2 ap = p - a;
836  ImVec2 ab_dir = b - a;
837  float ab_len = sqrtf(ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y);
838  ab_dir *= 1.0f / ab_len;
839  float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
840  if (dot < 0.0f)
841  return a;
842  if (dot > ab_len)
843  return b;
844  return a + ab_dir * dot;
845 }
846 
847 bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
848 {
849  bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
850  bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
851  bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
852  return ((b1 == b2) && (b2 == b3));
853 }
854 
855 void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
856 {
857  ImVec2 v0 = b - a;
858  ImVec2 v1 = c - a;
859  ImVec2 v2 = p - a;
860  const float denom = v0.x * v1.y - v1.x * v0.y;
861  out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
862  out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
863  out_u = 1.0f - out_v - out_w;
864 }
865 
866 ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
867 {
868  ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
869  ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
870  ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
871  float dist2_ab = ImLengthSqr(p - proj_ab);
872  float dist2_bc = ImLengthSqr(p - proj_bc);
873  float dist2_ca = ImLengthSqr(p - proj_ca);
874  float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
875  if (m == dist2_ab)
876  return proj_ab;
877  if (m == dist2_bc)
878  return proj_bc;
879  return proj_ca;
880 }
881 
882 int ImStricmp(const char* str1, const char* str2)
883 {
884  int d;
885  while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
886  return d;
887 }
888 
889 int ImStrnicmp(const char* str1, const char* str2, int count)
890 {
891  int d = 0;
892  while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
893  return d;
894 }
895 
896 void ImStrncpy(char* dst, const char* src, int count)
897 {
898  if (count < 1) return;
899  strncpy(dst, src, (size_t)count);
900  dst[count-1] = 0;
901 }
902 
903 char* ImStrdup(const char *str)
904 {
905  size_t len = strlen(str) + 1;
906  void* buff = ImGui::MemAlloc(len);
907  return (char*)memcpy(buff, (const void*)str, len);
908 }
909 
910 int ImStrlenW(const ImWchar* str)
911 {
912  int n = 0;
913  while (*str++) n++;
914  return n;
915 }
916 
917 const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
918 {
919  while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
920  buf_mid_line--;
921  return buf_mid_line;
922 }
923 
924 const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
925 {
926  if (!needle_end)
927  needle_end = needle + strlen(needle);
928 
929  const char un0 = (char)toupper(*needle);
930  while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
931  {
932  if (toupper(*haystack) == un0)
933  {
934  const char* b = needle + 1;
935  for (const char* a = haystack + 1; b < needle_end; a++, b++)
936  if (toupper(*a) != toupper(*b))
937  break;
938  if (b == needle_end)
939  return haystack;
940  }
941  haystack++;
942  }
943  return NULL;
944 }
945 
946 static const char* ImAtoi(const char* src, int* output)
947 {
948  int negative = 0;
949  if (*src == '-') { negative = 1; src++; }
950  if (*src == '+') { src++; }
951  int v = 0;
952  while (*src >= '0' && *src <= '9')
953  v = (v * 10) + (*src++ - '0');
954  *output = negative ? -v : v;
955  return src;
956 }
957 
958 // MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
959 // 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.
960 int ImFormatString(char* buf, int buf_size, const char* fmt, ...)
961 {
962  IM_ASSERT(buf_size > 0);
963  va_list args;
964  va_start(args, fmt);
965  int w = vsnprintf(buf, buf_size, fmt, args);
966  va_end(args);
967  if (w == -1 || w >= buf_size)
968  w = buf_size - 1;
969  buf[w] = 0;
970  return w;
971 }
972 
973 int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args)
974 {
975  IM_ASSERT(buf_size > 0);
976  int w = vsnprintf(buf, buf_size, fmt, args);
977  if (w == -1 || w >= buf_size)
978  w = buf_size - 1;
979  buf[w] = 0;
980  return w;
981 }
982 
983 // Pass data_size==0 for zero-terminated strings
984 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
985 ImU32 ImHash(const void* data, int data_size, ImU32 seed)
986 {
987  static ImU32 crc32_lut[256] = { 0 };
988  if (!crc32_lut[1])
989  {
990  const ImU32 polynomial = 0xEDB88320;
991  for (ImU32 i = 0; i < 256; i++)
992  {
993  ImU32 crc = i;
994  for (ImU32 j = 0; j < 8; j++)
995  crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial);
996  crc32_lut[i] = crc;
997  }
998  }
999 
1000  seed = ~seed;
1001  ImU32 crc = seed;
1002  const unsigned char* current = (const unsigned char*)data;
1003 
1004  if (data_size > 0)
1005  {
1006  // Known size
1007  while (data_size--)
1008  crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++];
1009  }
1010  else
1011  {
1012  // Zero-terminated string
1013  while (unsigned char c = *current++)
1014  {
1015  // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
1016  // Because this syntax is rarely used we are optimizing for the common case.
1017  // - If we reach ### in the string we discard the hash so far and reset to the seed.
1018  // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
1019  if (c == '#' && current[0] == '#' && current[1] == '#')
1020  crc = seed;
1021  crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1022  }
1023  }
1024  return ~crc;
1025 }
1026 
1027 //-----------------------------------------------------------------------------
1028 // ImText* helpers
1029 //-----------------------------------------------------------------------------
1030 
1031 // Convert UTF-8 to 32-bits character, process single character input.
1032 // Based on stb_from_utf8() from github.com/nothings/stb/
1033 // We handle UTF-8 decoding error by skipping forward.
1034 int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
1035 {
1036  unsigned int c = (unsigned int)-1;
1037  const unsigned char* str = (const unsigned char*)in_text;
1038  if (!(*str & 0x80))
1039  {
1040  c = (unsigned int)(*str++);
1041  *out_char = c;
1042  return 1;
1043  }
1044  if ((*str & 0xe0) == 0xc0)
1045  {
1046  *out_char = 0xFFFD; // will be invalid but not end of string
1047  if (in_text_end && in_text_end - (const char*)str < 2) return 1;
1048  if (*str < 0xc2) return 2;
1049  c = (unsigned int)((*str++ & 0x1f) << 6);
1050  if ((*str & 0xc0) != 0x80) return 2;
1051  c += (*str++ & 0x3f);
1052  *out_char = c;
1053  return 2;
1054  }
1055  if ((*str & 0xf0) == 0xe0)
1056  {
1057  *out_char = 0xFFFD; // will be invalid but not end of string
1058  if (in_text_end && in_text_end - (const char*)str < 3) return 1;
1059  if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
1060  if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
1061  c = (unsigned int)((*str++ & 0x0f) << 12);
1062  if ((*str & 0xc0) != 0x80) return 3;
1063  c += (unsigned int)((*str++ & 0x3f) << 6);
1064  if ((*str & 0xc0) != 0x80) return 3;
1065  c += (*str++ & 0x3f);
1066  *out_char = c;
1067  return 3;
1068  }
1069  if ((*str & 0xf8) == 0xf0)
1070  {
1071  *out_char = 0xFFFD; // will be invalid but not end of string
1072  if (in_text_end && in_text_end - (const char*)str < 4) return 1;
1073  if (*str > 0xf4) return 4;
1074  if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
1075  if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
1076  c = (unsigned int)((*str++ & 0x07) << 18);
1077  if ((*str & 0xc0) != 0x80) return 4;
1078  c += (unsigned int)((*str++ & 0x3f) << 12);
1079  if ((*str & 0xc0) != 0x80) return 4;
1080  c += (unsigned int)((*str++ & 0x3f) << 6);
1081  if ((*str & 0xc0) != 0x80) return 4;
1082  c += (*str++ & 0x3f);
1083  // utf-8 encodings of values used in surrogate pairs are invalid
1084  if ((c & 0xFFFFF800) == 0xD800) return 4;
1085  *out_char = c;
1086  return 4;
1087  }
1088  *out_char = 0;
1089  return 0;
1090 }
1091 
1092 int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
1093 {
1094  ImWchar* buf_out = buf;
1095  ImWchar* buf_end = buf + buf_size;
1096  while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1097  {
1098  unsigned int c;
1099  in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1100  if (c == 0)
1101  break;
1102  if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
1103  *buf_out++ = (ImWchar)c;
1104  }
1105  *buf_out = 0;
1106  if (in_text_remaining)
1107  *in_text_remaining = in_text;
1108  return (int)(buf_out - buf);
1109 }
1110 
1111 int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
1112 {
1113  int char_count = 0;
1114  while ((!in_text_end || in_text < in_text_end) && *in_text)
1115  {
1116  unsigned int c;
1117  in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1118  if (c == 0)
1119  break;
1120  if (c < 0x10000)
1121  char_count++;
1122  }
1123  return char_count;
1124 }
1125 
1126 // Based on stb_to_utf8() from github.com/nothings/stb/
1127 static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
1128 {
1129  if (c < 0x80)
1130  {
1131  buf[0] = (char)c;
1132  return 1;
1133  }
1134  if (c < 0x800)
1135  {
1136  if (buf_size < 2) return 0;
1137  buf[0] = (char)(0xc0 + (c >> 6));
1138  buf[1] = (char)(0x80 + (c & 0x3f));
1139  return 2;
1140  }
1141  if (c >= 0xdc00 && c < 0xe000)
1142  {
1143  return 0;
1144  }
1145  if (c >= 0xd800 && c < 0xdc00)
1146  {
1147  if (buf_size < 4) return 0;
1148  buf[0] = (char)(0xf0 + (c >> 18));
1149  buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
1150  buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
1151  buf[3] = (char)(0x80 + ((c ) & 0x3f));
1152  return 4;
1153  }
1154  //else if (c < 0x10000)
1155  {
1156  if (buf_size < 3) return 0;
1157  buf[0] = (char)(0xe0 + (c >> 12));
1158  buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
1159  buf[2] = (char)(0x80 + ((c ) & 0x3f));
1160  return 3;
1161  }
1162 }
1163 
1164 static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
1165 {
1166  if (c < 0x80) return 1;
1167  if (c < 0x800) return 2;
1168  if (c >= 0xdc00 && c < 0xe000) return 0;
1169  if (c >= 0xd800 && c < 0xdc00) return 4;
1170  return 3;
1171 }
1172 
1173 int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
1174 {
1175  char* buf_out = buf;
1176  const char* buf_end = buf + buf_size;
1177  while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1178  {
1179  unsigned int c = (unsigned int)(*in_text++);
1180  if (c < 0x80)
1181  *buf_out++ = (char)c;
1182  else
1183  buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c);
1184  }
1185  *buf_out = 0;
1186  return (int)(buf_out - buf);
1187 }
1188 
1189 int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
1190 {
1191  int bytes_count = 0;
1192  while ((!in_text_end || in_text < in_text_end) && *in_text)
1193  {
1194  unsigned int c = (unsigned int)(*in_text++);
1195  if (c < 0x80)
1196  bytes_count++;
1197  else
1198  bytes_count += ImTextCountUtf8BytesFromChar(c);
1199  }
1200  return bytes_count;
1201 }
1202 
1204 {
1205  float s = 1.0f/255.0f;
1206  return ImVec4(
1207  ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
1208  ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
1209  ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
1210  ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
1211 }
1212 
1214 {
1215  ImU32 out;
1216  out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
1217  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
1218  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
1219  out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
1220  return out;
1221 }
1222 
1223 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
1224 {
1225  ImGuiStyle& style = GImGui->Style;
1226  ImVec4 c = style.Colors[idx];
1227  c.w *= style.Alpha * alpha_mul;
1228  return ColorConvertFloat4ToU32(c);
1229 }
1230 
1232 {
1233  ImGuiStyle& style = GImGui->Style;
1234  ImVec4 c = col;
1235  c.w *= style.Alpha;
1236  return ColorConvertFloat4ToU32(c);
1237 }
1238 
1240 {
1241  ImGuiStyle& style = GImGui->Style;
1242  return style.Colors[idx];
1243 }
1244 
1246 {
1247  float style_alpha = GImGui->Style.Alpha;
1248  if (style_alpha >= 1.0f)
1249  return col;
1250  int a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
1251  a = (int)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
1252  return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
1253 }
1254 
1255 // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
1256 // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
1257 void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
1258 {
1259  float K = 0.f;
1260  if (g < b)
1261  {
1262  ImSwap(g, b);
1263  K = -1.f;
1264  }
1265  if (r < g)
1266  {
1267  ImSwap(r, g);
1268  K = -2.f / 6.f - K;
1269  }
1270 
1271  const float chroma = r - (g < b ? g : b);
1272  out_h = fabsf(K + (g - b) / (6.f * chroma + 1e-20f));
1273  out_s = chroma / (r + 1e-20f);
1274  out_v = r;
1275 }
1276 
1277 // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
1278 // also http://en.wikipedia.org/wiki/HSL_and_HSV
1279 void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
1280 {
1281  if (s == 0.0f)
1282  {
1283  // gray
1284  out_r = out_g = out_b = v;
1285  return;
1286  }
1287 
1288  h = fmodf(h, 1.0f) / (60.0f/360.0f);
1289  int i = (int)h;
1290  float f = h - (float)i;
1291  float p = v * (1.0f - s);
1292  float q = v * (1.0f - s * f);
1293  float t = v * (1.0f - s * (1.0f - f));
1294 
1295  switch (i)
1296  {
1297  case 0: out_r = v; out_g = t; out_b = p; break;
1298  case 1: out_r = q; out_g = v; out_b = p; break;
1299  case 2: out_r = p; out_g = v; out_b = t; break;
1300  case 3: out_r = p; out_g = q; out_b = v; break;
1301  case 4: out_r = t; out_g = p; out_b = v; break;
1302  case 5: default: out_r = v; out_g = p; out_b = q; break;
1303  }
1304 }
1305 
1306 FILE* ImFileOpen(const char* filename, const char* mode)
1307 {
1308 #if defined(_WIN32) && !defined(__CYGWIN__)
1309  // 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)
1310  const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1;
1311  const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
1312  ImVector<ImWchar> buf;
1313  buf.resize(filename_wsize + mode_wsize);
1314  ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL);
1315  ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL);
1316  return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]);
1317 #else
1318  return fopen(filename, mode);
1319 #endif
1320 }
1321 
1322 // Load file content into memory
1323 // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
1324 void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes)
1325 {
1326  IM_ASSERT(filename && file_open_mode);
1327  if (out_file_size)
1328  *out_file_size = 0;
1329 
1330  FILE* f;
1331  if ((f = ImFileOpen(filename, file_open_mode)) == NULL)
1332  return NULL;
1333 
1334  long file_size_signed;
1335  if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
1336  {
1337  fclose(f);
1338  return NULL;
1339  }
1340 
1341  int file_size = (int)file_size_signed;
1342  void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
1343  if (file_data == NULL)
1344  {
1345  fclose(f);
1346  return NULL;
1347  }
1348  if (fread(file_data, 1, (size_t)file_size, f) != (size_t)file_size)
1349  {
1350  fclose(f);
1351  ImGui::MemFree(file_data);
1352  return NULL;
1353  }
1354  if (padding_bytes > 0)
1355  memset((void *)(((char*)file_data) + file_size), 0, padding_bytes);
1356 
1357  fclose(f);
1358  if (out_file_size)
1359  *out_file_size = file_size;
1360 
1361  return file_data;
1362 }
1363 
1364 //-----------------------------------------------------------------------------
1365 // ImGuiStorage
1366 //-----------------------------------------------------------------------------
1367 
1368 // Helper: Key->value storage
1370 {
1371  Data.clear();
1372 }
1373 
1374 // std::lower_bound but without the bullshit
1376 {
1379  int count = (int)(last - first);
1380  while (count > 0)
1381  {
1382  int count2 = count / 2;
1383  ImVector<ImGuiStorage::Pair>::iterator mid = first + count2;
1384  if (mid->key < key)
1385  {
1386  first = ++mid;
1387  count -= count2 + 1;
1388  }
1389  else
1390  {
1391  count = count2;
1392  }
1393  }
1394  return first;
1395 }
1396 
1397 int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
1398 {
1399  ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1400  if (it == Data.end() || it->key != key)
1401  return default_val;
1402  return it->val_i;
1403 }
1404 
1405 bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
1406 {
1407  return GetInt(key, default_val ? 1 : 0) != 0;
1408 }
1409 
1410 float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
1411 {
1412  ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1413  if (it == Data.end() || it->key != key)
1414  return default_val;
1415  return it->val_f;
1416 }
1417 
1419 {
1420  ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1421  if (it == Data.end() || it->key != key)
1422  return NULL;
1423  return it->val_p;
1424 }
1425 
1426 // 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.
1427 int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
1428 {
1429  ImVector<Pair>::iterator it = LowerBound(Data, key);
1430  if (it == Data.end() || it->key != key)
1431  it = Data.insert(it, Pair(key, default_val));
1432  return &it->val_i;
1433 }
1434 
1435 bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
1436 {
1437  return (bool*)GetIntRef(key, default_val ? 1 : 0);
1438 }
1439 
1440 float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
1441 {
1442  ImVector<Pair>::iterator it = LowerBound(Data, key);
1443  if (it == Data.end() || it->key != key)
1444  it = Data.insert(it, Pair(key, default_val));
1445  return &it->val_f;
1446 }
1447 
1448 void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
1449 {
1450  ImVector<Pair>::iterator it = LowerBound(Data, key);
1451  if (it == Data.end() || it->key != key)
1452  it = Data.insert(it, Pair(key, default_val));
1453  return &it->val_p;
1454 }
1455 
1456 // FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
1457 void ImGuiStorage::SetInt(ImGuiID key, int val)
1458 {
1459  ImVector<Pair>::iterator it = LowerBound(Data, key);
1460  if (it == Data.end() || it->key != key)
1461  {
1462  Data.insert(it, Pair(key, val));
1463  return;
1464  }
1465  it->val_i = val;
1466 }
1467 
1468 void ImGuiStorage::SetBool(ImGuiID key, bool val)
1469 {
1470  SetInt(key, val ? 1 : 0);
1471 }
1472 
1473 void ImGuiStorage::SetFloat(ImGuiID key, float val)
1474 {
1475  ImVector<Pair>::iterator it = LowerBound(Data, key);
1476  if (it == Data.end() || it->key != key)
1477  {
1478  Data.insert(it, Pair(key, val));
1479  return;
1480  }
1481  it->val_f = val;
1482 }
1483 
1484 void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
1485 {
1486  ImVector<Pair>::iterator it = LowerBound(Data, key);
1487  if (it == Data.end() || it->key != key)
1488  {
1489  Data.insert(it, Pair(key, val));
1490  return;
1491  }
1492  it->val_p = val;
1493 }
1494 
1496 {
1497  for (int i = 0; i < Data.Size; i++)
1498  Data[i].val_i = v;
1499 }
1500 
1501 //-----------------------------------------------------------------------------
1502 // ImGuiTextFilter
1503 //-----------------------------------------------------------------------------
1504 
1505 // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
1506 ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
1507 {
1508  if (default_filter)
1509  {
1510  ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
1511  Build();
1512  }
1513  else
1514  {
1515  InputBuf[0] = 0;
1516  CountGrep = 0;
1517  }
1518 }
1519 
1520 bool ImGuiTextFilter::Draw(const char* label, float width)
1521 {
1522  if (width != 0.0f)
1523  ImGui::PushItemWidth(width);
1524  bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
1525  if (width != 0.0f)
1527  if (value_changed)
1528  Build();
1529  return value_changed;
1530 }
1531 
1533 {
1534  out.resize(0);
1535  const char* wb = b;
1536  const char* we = wb;
1537  while (we < e)
1538  {
1539  if (*we == separator)
1540  {
1541  out.push_back(TextRange(wb, we));
1542  wb = we + 1;
1543  }
1544  we++;
1545  }
1546  if (wb != we)
1547  out.push_back(TextRange(wb, we));
1548 }
1549 
1551 {
1552  Filters.resize(0);
1553  TextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
1554  input_range.split(',', Filters);
1555 
1556  CountGrep = 0;
1557  for (int i = 0; i != Filters.Size; i++)
1558  {
1559  Filters[i].trim_blanks();
1560  if (Filters[i].empty())
1561  continue;
1562  if (Filters[i].front() != '-')
1563  CountGrep += 1;
1564  }
1565 }
1566 
1567 bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
1568 {
1569  if (Filters.empty())
1570  return true;
1571 
1572  if (text == NULL)
1573  text = "";
1574 
1575  for (int i = 0; i != Filters.Size; i++)
1576  {
1577  const TextRange& f = Filters[i];
1578  if (f.empty())
1579  continue;
1580  if (f.front() == '-')
1581  {
1582  // Subtract
1583  if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL)
1584  return false;
1585  }
1586  else
1587  {
1588  // Grep
1589  if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)
1590  return true;
1591  }
1592  }
1593 
1594  // Implicit * grep
1595  if (CountGrep == 0)
1596  return true;
1597 
1598  return false;
1599 }
1600 
1601 //-----------------------------------------------------------------------------
1602 // ImGuiTextBuffer
1603 //-----------------------------------------------------------------------------
1604 
1605 // On some platform vsnprintf() takes va_list by reference and modifies it.
1606 // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
1607 #ifndef va_copy
1608 #define va_copy(dest, src) (dest = src)
1609 #endif
1610 
1611 // Helper: Text buffer for logging/accumulating text
1612 void ImGuiTextBuffer::appendv(const char* fmt, va_list args)
1613 {
1614  va_list args_copy;
1615  va_copy(args_copy, args);
1616 
1617  int len = vsnprintf(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
1618  if (len <= 0)
1619  return;
1620 
1621  const int write_off = Buf.Size;
1622  const int needed_sz = write_off + len;
1623  if (write_off + len >= Buf.Capacity)
1624  {
1625  int double_capacity = Buf.Capacity * 2;
1626  Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity);
1627  }
1628 
1629  Buf.resize(needed_sz);
1630  ImFormatStringV(&Buf[write_off] - 1, len+1, fmt, args_copy);
1631 }
1632 
1633 void ImGuiTextBuffer::append(const char* fmt, ...)
1634 {
1635  va_list args;
1636  va_start(args, fmt);
1637  appendv(fmt, args);
1638  va_end(args);
1639 }
1640 
1641 //-----------------------------------------------------------------------------
1642 // ImGuiSimpleColumns
1643 //-----------------------------------------------------------------------------
1644 
1646 {
1647  Count = 0;
1648  Spacing = Width = NextWidth = 0.0f;
1649  memset(Pos, 0, sizeof(Pos));
1650  memset(NextWidths, 0, sizeof(NextWidths));
1651 }
1652 
1653 void ImGuiSimpleColumns::Update(int count, float spacing, bool clear)
1654 {
1655  IM_ASSERT(Count <= IM_ARRAYSIZE(Pos));
1656  Count = count;
1657  Width = NextWidth = 0.0f;
1658  Spacing = spacing;
1659  if (clear) memset(NextWidths, 0, sizeof(NextWidths));
1660  for (int i = 0; i < Count; i++)
1661  {
1662  if (i > 0 && NextWidths[i] > 0.0f)
1663  Width += Spacing;
1664  Pos[i] = (float)(int)Width;
1665  Width += NextWidths[i];
1666  NextWidths[i] = 0.0f;
1667  }
1668 }
1669 
1670 float ImGuiSimpleColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double
1671 {
1672  NextWidth = 0.0f;
1673  NextWidths[0] = ImMax(NextWidths[0], w0);
1674  NextWidths[1] = ImMax(NextWidths[1], w1);
1675  NextWidths[2] = ImMax(NextWidths[2], w2);
1676  for (int i = 0; i < 3; i++)
1677  NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f);
1678  return ImMax(Width, NextWidth);
1679 }
1680 
1682 {
1683  return ImMax(0.0f, avail_w - Width);
1684 }
1685 
1686 //-----------------------------------------------------------------------------
1687 // ImGuiListClipper
1688 //-----------------------------------------------------------------------------
1689 
1690 static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
1691 {
1692  // Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor.
1693  // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue. Consider moving within SetCursorXXX functions?
1694  ImGui::SetCursorPosY(pos_y);
1696  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.
1697  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.
1698  if (window->DC.ColumnsCount > 1)
1699  window->DC.ColumnsCellMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
1700 }
1701 
1702 // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
1703 // Use case B: Begin() called from constructor with items_height>0
1704 // 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.
1705 void ImGuiListClipper::Begin(int count, float items_height)
1706 {
1707  StartPosY = ImGui::GetCursorPosY();
1708  ItemsHeight = items_height;
1709  ItemsCount = count;
1710  StepNo = 0;
1711  DisplayEnd = DisplayStart = -1;
1712  if (ItemsHeight > 0.0f)
1713  {
1714  ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
1715  if (DisplayStart > 0)
1716  SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
1717  StepNo = 2;
1718  }
1719 }
1720 
1722 {
1723  if (ItemsCount < 0)
1724  return;
1725  // 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.
1726  if (ItemsCount < INT_MAX)
1727  SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
1728  ItemsCount = -1;
1729  StepNo = 3;
1730 }
1731 
1733 {
1734  if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
1735  {
1736  ItemsCount = -1;
1737  return false;
1738  }
1739  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.
1740  {
1741  DisplayStart = 0;
1742  DisplayEnd = 1;
1743  StartPosY = ImGui::GetCursorPosY();
1744  StepNo = 1;
1745  return true;
1746  }
1747  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.
1748  {
1749  if (ItemsCount == 1) { ItemsCount = -1; return false; }
1750  float items_height = ImGui::GetCursorPosY() - StartPosY;
1751  IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically
1752  Begin(ItemsCount-1, items_height);
1753  DisplayStart++;
1754  DisplayEnd++;
1755  StepNo = 3;
1756  return true;
1757  }
1758  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.
1759  {
1760  IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
1761  StepNo = 3;
1762  return true;
1763  }
1764  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.
1765  End();
1766  return false;
1767 }
1768 
1769 //-----------------------------------------------------------------------------
1770 // ImGuiWindow
1771 //-----------------------------------------------------------------------------
1772 
1773 ImGuiWindow::ImGuiWindow(const char* name)
1774 {
1775  Name = ImStrdup(name);
1776  ID = ImHash(name, 0);
1777  IDStack.push_back(ID);
1778  Flags = 0;
1779  OrderWithinParent = 0;
1780  PosFloat = Pos = ImVec2(0.0f, 0.0f);
1781  Size = SizeFull = ImVec2(0.0f, 0.0f);
1782  SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
1783  WindowPadding = ImVec2(0.0f, 0.0f);
1784  MoveId = GetID("#MOVE");
1785  Scroll = ImVec2(0.0f, 0.0f);
1786  ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
1787  ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
1788  ScrollbarX = ScrollbarY = false;
1789  ScrollbarSizes = ImVec2(0.0f, 0.0f);
1790  BorderSize = 0.0f;
1791  Active = WasActive = false;
1792  Accessed = false;
1793  Collapsed = false;
1794  SkipItems = false;
1795  Appearing = false;
1796  BeginCount = 0;
1797  PopupId = 0;
1798  AutoFitFramesX = AutoFitFramesY = -1;
1799  AutoFitOnlyGrows = false;
1800  AutoFitChildAxises = 0x00;
1801  AutoPosLastDirection = -1;
1802  HiddenFrames = 0;
1803  SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
1804  SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
1805 
1806  LastFrameActive = -1;
1807  ItemWidthDefault = 0.0f;
1808  FontWindowScale = 1.0f;
1809 
1810  DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList));
1811  IM_PLACEMENT_NEW(DrawList) ImDrawList();
1812  DrawList->_OwnerName = Name;
1813  ParentWindow = NULL;
1814  RootWindow = NULL;
1815  RootNonPopupWindow = NULL;
1816 
1817  FocusIdxAllCounter = FocusIdxTabCounter = -1;
1818  FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX;
1819  FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX;
1820 }
1821 
1823 {
1824  DrawList->~ImDrawList();
1825  ImGui::MemFree(DrawList);
1826  DrawList = NULL;
1827  ImGui::MemFree(Name);
1828  Name = NULL;
1829 }
1830 
1831 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
1832 {
1833  ImGuiID seed = IDStack.back();
1834  ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
1835  ImGui::KeepAliveID(id);
1836  return id;
1837 }
1838 
1839 ImGuiID ImGuiWindow::GetID(const void* ptr)
1840 {
1841  ImGuiID seed = IDStack.back();
1842  ImGuiID id = ImHash(&ptr, sizeof(void*), seed);
1843  ImGui::KeepAliveID(id);
1844  return id;
1845 }
1846 
1847 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
1848 {
1849  ImGuiID seed = IDStack.back();
1850  return ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
1851 }
1852 
1853 //-----------------------------------------------------------------------------
1854 // Internal API exposed in imgui_internal.h
1855 //-----------------------------------------------------------------------------
1856 
1857 static void SetCurrentWindow(ImGuiWindow* window)
1858 {
1859  ImGuiContext& g = *GImGui;
1860  g.CurrentWindow = window;
1861  if (window)
1862  g.FontSize = window->CalcFontSize();
1863 }
1864 
1866 {
1867  ImGuiContext& g = *GImGui;
1869  return g.CurrentWindowStack[(unsigned int)g.CurrentWindowStack.Size - 2];
1870 }
1871 
1873 {
1874  ImGuiContext& g = *GImGui;
1875  g.ActiveIdIsJustActivated = (g.ActiveId != id);
1876  g.ActiveId = id;
1877  g.ActiveIdAllowOverlap = false;
1878  g.ActiveIdIsAlive |= (id != 0);
1879  g.ActiveIdWindow = window;
1880 }
1881 
1883 {
1884  SetActiveID(0, NULL);
1885 }
1886 
1888 {
1889  ImGuiContext& g = *GImGui;
1890  g.HoveredId = id;
1891  g.HoveredIdAllowOverlap = false;
1892 }
1893 
1895 {
1896  ImGuiContext& g = *GImGui;
1897  if (g.ActiveId == id)
1898  g.ActiveIdIsAlive = true;
1899 }
1900 
1901 static inline bool IsWindowContentHoverable(ImGuiWindow* window)
1902 {
1903  // An active popup disable hovering on other windows (apart from its own children)
1904  // FIXME-OPT: This could be cached/stored within the window.
1905  ImGuiContext& g = *GImGui;
1906  if (g.NavWindow)
1907  if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
1908  if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasActive && focused_root_window != window->RootWindow)
1909  return false;
1910 
1911  return true;
1912 }
1913 
1914 // Advance cursor given item size for layout.
1915 void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
1916 {
1917  ImGuiWindow* window = GetCurrentWindow();
1918  if (window->SkipItems)
1919  return;
1920 
1921  // Always align ourselves on pixel boundaries
1922  ImGuiContext& g = *GImGui;
1923  const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
1924  const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
1925  //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]
1926  window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
1927  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));
1928  window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
1929  window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
1930  //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
1931 
1932  window->DC.PrevLineHeight = line_height;
1933  window->DC.PrevLineTextBaseOffset = text_base_offset;
1934  window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f;
1935 
1936  // Horizontal layout mode
1937  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
1938  SameLine();
1939 }
1940 
1941 void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
1942 {
1943  ItemSize(bb.GetSize(), text_offset_y);
1944 }
1945 
1946 // Declare item bounding box for clipping and interaction.
1947 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
1948 // declares their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
1949 bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id)
1950 {
1951  ImGuiContext& g = *GImGui;
1952  ImGuiWindow* window = g.CurrentWindow;
1953  const bool is_clipped = IsClippedEx(bb, id, false);
1954  window->DC.LastItemId = id ? *id : 0;
1955  window->DC.LastItemRect = bb;
1956  window->DC.LastItemRectHoveredRect = false;
1957  if (is_clipped)
1958  return false;
1959  //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
1960 
1961  // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
1963  return true;
1964 }
1965 
1966 // This is roughly matching the behavior of internal-facing ItemHoverable() which is
1967 // - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered())
1969 {
1970  ImGuiContext& g = *GImGui;
1971 
1972  ImGuiWindow* window = g.CurrentWindow;
1973  if (!window->DC.LastItemRectHoveredRect)
1974  return false;
1975  if (g.HoveredWindow != window)
1976  return false;
1977  if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
1978  return false;
1979  if (!IsWindowContentHoverable(window))
1980  return false;
1981  return true;
1982 }
1983 
1985 {
1986  ImGuiWindow* window = GetCurrentWindowRead();
1987  return window->DC.LastItemRectHoveredRect;
1988 }
1989 
1990 // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
1992 {
1993  ImGuiContext& g = *GImGui;
1994  if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
1995  return false;
1996 
1997  ImGuiWindow* window = g.CurrentWindow;
1998  if (g.HoveredWindow != window)
1999  return false;
2000  if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
2001  return false;
2002  if (!IsMouseHoveringRect(bb.Min, bb.Max))
2003  return false;
2004  if (!IsWindowContentHoverable(window))
2005  return false;
2006 
2007  SetHoveredID(id);
2008  return true;
2009 }
2010 
2011 bool ImGui::IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when_logged)
2012 {
2013  ImGuiContext& g = *GImGui;
2014  ImGuiWindow* window = GetCurrentWindowRead();
2015  if (!bb.Overlaps(window->ClipRect))
2016  if (!id || *id != g.ActiveId)
2017  if (clip_even_when_logged || !g.LogEnabled)
2018  return true;
2019  return false;
2020 }
2021 
2022 bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop)
2023 {
2024  ImGuiContext& g = *GImGui;
2025 
2026  const bool allow_keyboard_focus = (window->DC.ItemFlags & ImGuiItemFlags_AllowKeyboardFocus) != 0;
2027  window->FocusIdxAllCounter++;
2028  if (allow_keyboard_focus)
2029  window->FocusIdxTabCounter++;
2030 
2031  // Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item.
2032  // Note that we can always TAB out of a widget that doesn't allow tabbing in.
2033  if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab))
2034  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.
2035 
2036  if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent)
2037  return true;
2038 
2039  if (allow_keyboard_focus)
2040  if (window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent)
2041  return true;
2042 
2043  return false;
2044 }
2045 
2047 {
2048  window->FocusIdxAllCounter--;
2049  window->FocusIdxTabCounter--;
2050 }
2051 
2052 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y)
2053 {
2054  ImGuiContext& g = *GImGui;
2055  ImVec2 content_max;
2056  if (size.x < 0.0f || size.y < 0.0f)
2057  content_max = g.CurrentWindow->Pos + GetContentRegionMax();
2058  if (size.x <= 0.0f)
2059  size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x;
2060  if (size.y <= 0.0f)
2061  size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y;
2062  return size;
2063 }
2064 
2065 float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
2066 {
2067  if (wrap_pos_x < 0.0f)
2068  return 0.0f;
2069 
2070  ImGuiWindow* window = GetCurrentWindowRead();
2071  if (wrap_pos_x == 0.0f)
2072  wrap_pos_x = GetContentRegionMax().x + window->Pos.x;
2073  else if (wrap_pos_x > 0.0f)
2074  wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
2075 
2076  return ImMax(wrap_pos_x - pos.x, 1.0f);
2077 }
2078 
2079 //-----------------------------------------------------------------------------
2080 
2081 void* ImGui::MemAlloc(size_t sz)
2082 {
2083  GImGui->IO.MetricsAllocs++;
2084  return GImGui->IO.MemAllocFn(sz);
2085 }
2086 
2087 void ImGui::MemFree(void* ptr)
2088 {
2089  if (ptr) GImGui->IO.MetricsAllocs--;
2090  return GImGui->IO.MemFreeFn(ptr);
2091 }
2092 
2094 {
2095  return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : "";
2096 }
2097 
2098 void ImGui::SetClipboardText(const char* text)
2099 {
2100  if (GImGui->IO.SetClipboardTextFn)
2101  GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text);
2102 }
2103 
2104 const char* ImGui::GetVersion()
2105 {
2106  return IMGUI_VERSION;
2107 }
2108 
2109 // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
2110 // 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
2112 {
2113  return GImGui;
2114 }
2115 
2117 {
2118 #ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
2119  IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
2120 #else
2121  GImGui = ctx;
2122 #endif
2123 }
2124 
2125 ImGuiContext* ImGui::CreateContext(void* (*malloc_fn)(size_t), void (*free_fn)(void*))
2126 {
2127  if (!malloc_fn) malloc_fn = malloc;
2128  ImGuiContext* ctx = (ImGuiContext*)malloc_fn(sizeof(ImGuiContext));
2129  IM_PLACEMENT_NEW(ctx) ImGuiContext();
2130  ctx->IO.MemAllocFn = malloc_fn;
2131  ctx->IO.MemFreeFn = free_fn ? free_fn : free;
2132  return ctx;
2133 }
2134 
2136 {
2137  void (*free_fn)(void*) = ctx->IO.MemFreeFn;
2138  ctx->~ImGuiContext();
2139  free_fn(ctx);
2140  if (GImGui == ctx)
2141  SetCurrentContext(NULL);
2142 }
2143 
2145 {
2146  return GImGui->IO;
2147 }
2148 
2150 {
2151  return GImGui->Style;
2152 }
2153 
2154 // Same value as passed to your RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame()
2156 {
2157  return GImGui->RenderDrawData.Valid ? &GImGui->RenderDrawData : NULL;
2158 }
2159 
2161 {
2162  return GImGui->Time;
2163 }
2164 
2166 {
2167  return GImGui->FrameCount;
2168 }
2169 
2171 {
2172  ImGuiContext& g = *GImGui;
2173 
2174  // Check user data
2175  IM_ASSERT(g.IO.DeltaTime >= 0.0f); // Need a positive DeltaTime (zero is tolerated but will cause some timing issues)
2176  IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f);
2177  IM_ASSERT(g.IO.Fonts->Fonts.Size > 0); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
2178  IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
2179  IM_ASSERT(g.Style.CurveTessellationTol > 0.0f); // Invalid style setting
2180  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)
2181 
2182  // Initialize on first frame
2183  if (!g.Initialized)
2185 
2186  SetCurrentFont(GetDefaultFont());
2187  IM_ASSERT(g.Font->IsLoaded());
2188 
2189  g.Time += g.IO.DeltaTime;
2190  g.FrameCount += 1;
2191  g.TooltipOverrideCount = 0;
2192  g.OverlayDrawList.Clear();
2195 
2196  // Mark rendering data as invalid to prevent user who may have a handle on it to use it
2197  g.RenderDrawData.Valid = false;
2198  g.RenderDrawData.CmdLists = NULL;
2200 
2201  // Clear reference to active widget if the widget isn't alive anymore
2203  g.HoveredId = 0;
2204  g.HoveredIdAllowOverlap = false;
2205  if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
2206  ClearActiveID();
2208  g.ActiveIdIsAlive = false;
2209  g.ActiveIdIsJustActivated = false;
2211  g.ScalarAsInputTextId = 0;
2212 
2213  // Update keyboard input state
2215  for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
2216  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;
2217 
2218  // Update mouse input state
2219  // 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
2221  g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
2222  else
2223  g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
2224  g.IO.MousePosPrev = g.IO.MousePos;
2225  for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
2226  {
2227  g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
2228  g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
2230  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;
2231  g.IO.MouseDoubleClicked[i] = false;
2232  if (g.IO.MouseClicked[i])
2233  {
2234  if (g.Time - g.IO.MouseClickedTime[i] < g.IO.MouseDoubleClickTime)
2235  {
2237  g.IO.MouseDoubleClicked[i] = true;
2238  g.IO.MouseClickedTime[i] = -FLT_MAX; // so the third click isn't turned into a double-click
2239  }
2240  else
2241  {
2242  g.IO.MouseClickedTime[i] = g.Time;
2243  }
2244  g.IO.MouseClickedPos[i] = g.IO.MousePos;
2245  g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
2246  }
2247  else if (g.IO.MouseDown[i])
2248  {
2249  g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(g.IO.MousePos - g.IO.MouseClickedPos[i]));
2250  }
2251  }
2252 
2253  // Calculate frame-rate for the user, as a purely luxurious feature
2258 
2259  // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows.
2261  {
2265  if (g.IO.MouseDown[0])
2266  {
2268  if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
2269  MarkIniSettingsDirty(g.MovedWindow->RootWindow);
2271  }
2272  else
2273  {
2274  ClearActiveID();
2275  g.MovedWindow = NULL;
2276  g.MovedWindowMoveId = 0;
2277  }
2278  }
2279  else
2280  {
2281  g.MovedWindow = NULL;
2282  g.MovedWindowMoveId = 0;
2283  }
2284 
2285  // Delay saving settings so we don't spam disk too much
2286  if (g.SettingsDirtyTimer > 0.0f)
2287  {
2289  if (g.SettingsDirtyTimer <= 0.0f)
2290  SaveIniSettingsToDisk(g.IO.IniFilename);
2291  }
2292 
2293  // Find the window we are hovering. Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow
2294  g.HoveredWindow = g.MovedWindow ? g.MovedWindow : FindHoveredWindow(g.IO.MousePos, false);
2297  else
2298  g.HoveredRootWindow = g.MovedWindow ? g.MovedWindow->RootWindow : FindHoveredWindow(g.IO.MousePos, true);
2299 
2300  if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow())
2301  {
2302  g.ModalWindowDarkeningRatio = ImMin(g.ModalWindowDarkeningRatio + g.IO.DeltaTime * 6.0f, 1.0f);
2303  ImGuiWindow* window = g.HoveredRootWindow;
2304  while (window && window != modal_window)
2305  window = window->ParentWindow;
2306  if (!window)
2307  g.HoveredRootWindow = g.HoveredWindow = NULL;
2308  }
2309  else
2310  {
2311  g.ModalWindowDarkeningRatio = 0.0f;
2312  }
2313 
2314  // Are we using inputs? Tell user so they can capture/discard the inputs away from the rest of their application.
2315  // When clicking outside of a window we assume the click is owned by the application and won't request capture. We need to track click ownership.
2316  int mouse_earliest_button_down = -1;
2317  bool mouse_any_down = false;
2318  for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
2319  {
2320  if (g.IO.MouseClicked[i])
2321  g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty());
2322  mouse_any_down |= g.IO.MouseDown[i];
2323  if (g.IO.MouseDown[i])
2324  if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[mouse_earliest_button_down] > g.IO.MouseClickedTime[i])
2325  mouse_earliest_button_down = i;
2326  }
2327  bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
2328  if (g.WantCaptureMouseNextFrame != -1)
2330  else
2331  g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
2333  g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : 0;
2336  g.OsImePosRequest = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
2337 
2338  // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
2339  if (!mouse_avail_to_imgui)
2340  g.HoveredWindow = g.HoveredRootWindow = NULL;
2341 
2342  // Scale & Scrolling
2343  if (g.HoveredWindow && g.IO.MouseWheel != 0.0f && !g.HoveredWindow->Collapsed)
2344  {
2345  ImGuiWindow* window = g.HoveredWindow;
2346  if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
2347  {
2348  // Zoom / Scale window
2349  const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
2350  const float scale = new_font_scale / window->FontWindowScale;
2351  window->FontWindowScale = new_font_scale;
2352 
2353  const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
2354  window->Pos += offset;
2355  window->PosFloat += offset;
2356  window->Size *= scale;
2357  window->SizeFull *= scale;
2358  }
2359  else if (!g.IO.KeyCtrl && !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
2360  {
2361  // Scroll
2362  const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5;
2363  SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * window->CalcFontSize() * scroll_lines);
2364  }
2365  }
2366 
2367  // Pressing TAB activate widget focus
2368  // NB: Don't discard FocusedWindow if it isn't active, so that a window that go on/off programatically won't lose its keyboard focus.
2369  if (g.ActiveId == 0 && g.NavWindow != NULL && g.NavWindow->Active && IsKeyPressedMap(ImGuiKey_Tab, false))
2371 
2372  // Mark all windows as not visible
2373  for (int i = 0; i != g.Windows.Size; i++)
2374  {
2375  ImGuiWindow* window = g.Windows[i];
2376  window->WasActive = window->Active;
2377  window->Active = false;
2378  window->Accessed = false;
2379  }
2380 
2381  // Closing the focused window restore focus to the first active root window in descending z-order
2382  if (g.NavWindow && !g.NavWindow->WasActive)
2383  for (int i = g.Windows.Size-1; i >= 0; i--)
2384  if (g.Windows[i]->WasActive && !(g.Windows[i]->Flags & ImGuiWindowFlags_ChildWindow))
2385  {
2386  FocusWindow(g.Windows[i]);
2387  break;
2388  }
2389 
2390  // No window should be open at the beginning of the frame.
2391  // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
2394  CloseInactivePopups();
2395 
2396  // Create implicit window - we will only render it if the user has added something to it.
2397  // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
2399  ImGui::Begin("Debug##Default");
2400 }
2401 
2403 {
2404  ImGuiContext& g = *GImGui;
2406  IM_PLACEMENT_NEW(g.LogClipboard) ImGuiTextBuffer();
2407 
2408  IM_ASSERT(g.Settings.empty());
2409  LoadIniSettingsFromDisk(g.IO.IniFilename);
2410  g.Initialized = true;
2411 }
2412 
2413 // This function is merely here to free heap allocations.
2415 {
2416  ImGuiContext& g = *GImGui;
2417 
2418  // 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)
2419  if (g.IO.Fonts) // Testing for NULL to allow user to NULLify in case of running Shutdown() on multiple contexts. Bit hacky.
2420  g.IO.Fonts->Clear();
2421 
2422  // Cleanup of other data are conditional on actually having initialize ImGui.
2423  if (!g.Initialized)
2424  return;
2425 
2426  SaveIniSettingsToDisk(g.IO.IniFilename);
2427 
2428  for (int i = 0; i < g.Windows.Size; i++)
2429  {
2430  g.Windows[i]->~ImGuiWindow();
2431  ImGui::MemFree(g.Windows[i]);
2432  }
2433  g.Windows.clear();
2435  g.CurrentWindow = NULL;
2437  g.NavWindow = NULL;
2438  g.HoveredWindow = NULL;
2439  g.HoveredRootWindow = NULL;
2440  g.ActiveIdWindow = NULL;
2441  g.MovedWindow = NULL;
2442  for (int i = 0; i < g.Settings.Size; i++)
2443  ImGui::MemFree(g.Settings[i].Name);
2444  g.Settings.clear();
2445  g.ColorModifiers.clear();
2446  g.StyleModifiers.clear();
2447  g.FontStack.clear();
2448  g.OpenPopupStack.clear();
2452  for (int i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
2453  g.RenderDrawLists[i].clear();
2455  g.PrivateClipboard.clear();
2459 
2460  if (g.LogFile && g.LogFile != stdout)
2461  {
2462  fclose(g.LogFile);
2463  g.LogFile = NULL;
2464  }
2465  if (g.LogClipboard)
2466  {
2467  g.LogClipboard->~ImGuiTextBuffer();
2469  }
2470 
2471  g.Initialized = false;
2472 }
2473 
2474 static ImGuiIniData* FindWindowSettings(const char* name)
2475 {
2476  ImGuiContext& g = *GImGui;
2477  ImGuiID id = ImHash(name, 0);
2478  for (int i = 0; i != g.Settings.Size; i++)
2479  {
2480  ImGuiIniData* ini = &g.Settings[i];
2481  if (ini->Id == id)
2482  return ini;
2483  }
2484  return NULL;
2485 }
2486 
2487 static ImGuiIniData* AddWindowSettings(const char* name)
2488 {
2489  GImGui->Settings.resize(GImGui->Settings.Size + 1);
2490  ImGuiIniData* ini = &GImGui->Settings.back();
2491  ini->Name = ImStrdup(name);
2492  ini->Id = ImHash(name, 0);
2493  ini->Collapsed = false;
2494  ini->Pos = ImVec2(FLT_MAX,FLT_MAX);
2495  ini->Size = ImVec2(0,0);
2496  return ini;
2497 }
2498 
2499 // Zero-tolerance, poor-man .ini parsing
2500 // FIXME: Write something less rubbish
2501 static void LoadIniSettingsFromDisk(const char* ini_filename)
2502 {
2503  ImGuiContext& g = *GImGui;
2504  if (!ini_filename)
2505  return;
2506 
2507  int file_size;
2508  char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_size, 1);
2509  if (!file_data)
2510  return;
2511 
2512  ImGuiIniData* settings = NULL;
2513  const char* buf_end = file_data + file_size;
2514  for (const char* line_start = file_data; line_start < buf_end; )
2515  {
2516  const char* line_end = line_start;
2517  while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
2518  line_end++;
2519 
2520  if (line_start[0] == '[' && line_end > line_start && line_end[-1] == ']')
2521  {
2522  char name[64];
2523  ImFormatString(name, IM_ARRAYSIZE(name), "%.*s", (int)(line_end-line_start-2), line_start+1);
2524  settings = FindWindowSettings(name);
2525  if (!settings)
2526  settings = AddWindowSettings(name);
2527  }
2528  else if (settings)
2529  {
2530  float x, y;
2531  int i;
2532  if (sscanf(line_start, "Pos=%f,%f", &x, &y) == 2)
2533  settings->Pos = ImVec2(x, y);
2534  else if (sscanf(line_start, "Size=%f,%f", &x, &y) == 2)
2535  settings->Size = ImMax(ImVec2(x, y), g.Style.WindowMinSize);
2536  else if (sscanf(line_start, "Collapsed=%d", &i) == 1)
2537  settings->Collapsed = (i != 0);
2538  }
2539 
2540  line_start = line_end+1;
2541  }
2542 
2543  ImGui::MemFree(file_data);
2544 }
2545 
2546 static void SaveIniSettingsToDisk(const char* ini_filename)
2547 {
2548  ImGuiContext& g = *GImGui;
2549  g.SettingsDirtyTimer = 0.0f;
2550  if (!ini_filename)
2551  return;
2552 
2553  // Gather data from windows that were active during this session
2554  for (int i = 0; i != g.Windows.Size; i++)
2555  {
2556  ImGuiWindow* window = g.Windows[i];
2558  continue;
2559  ImGuiIniData* settings = FindWindowSettings(window->Name);
2560  if (!settings) // This will only return NULL in the rare instance where the window was first created with ImGuiWindowFlags_NoSavedSettings then had the flag disabled later on. We don't bind settings in this case (bug #1000).
2561  continue;
2562  settings->Pos = window->Pos;
2563  settings->Size = window->SizeFull;
2564  settings->Collapsed = window->Collapsed;
2565  }
2566 
2567  // Write .ini file
2568  // If a window wasn't opened in this session we preserve its settings
2569  FILE* f = ImFileOpen(ini_filename, "wt");
2570  if (!f)
2571  return;
2572  for (int i = 0; i != g.Settings.Size; i++)
2573  {
2574  const ImGuiIniData* settings = &g.Settings[i];
2575  if (settings->Pos.x == FLT_MAX)
2576  continue;
2577  const char* name = settings->Name;
2578  if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
2579  name = p;
2580  fprintf(f, "[%s]\n", name);
2581  fprintf(f, "Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
2582  fprintf(f, "Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
2583  fprintf(f, "Collapsed=%d\n", settings->Collapsed);
2584  fprintf(f, "\n");
2585  }
2586 
2587  fclose(f);
2588 }
2589 
2590 static void MarkIniSettingsDirty(ImGuiWindow* window)
2591 {
2592  ImGuiContext& g = *GImGui;
2593  if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
2594  if (g.SettingsDirtyTimer <= 0.0f)
2596 }
2597 
2598 // FIXME: Add a more explicit sort order in the window structure.
2599 static int ChildWindowComparer(const void* lhs, const void* rhs)
2600 {
2601  const ImGuiWindow* a = *(const ImGuiWindow**)lhs;
2602  const ImGuiWindow* b = *(const ImGuiWindow**)rhs;
2603  if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
2604  return d;
2605  if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
2606  return d;
2607  if (int d = (a->Flags & ImGuiWindowFlags_ComboBox) - (b->Flags & ImGuiWindowFlags_ComboBox))
2608  return d;
2609  return (a->OrderWithinParent - b->OrderWithinParent);
2610 }
2611 
2612 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>& out_sorted_windows, ImGuiWindow* window)
2613 {
2614  out_sorted_windows.push_back(window);
2615  if (window->Active)
2616  {
2617  int count = window->DC.ChildWindows.Size;
2618  if (count > 1)
2619  qsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
2620  for (int i = 0; i < count; i++)
2621  {
2622  ImGuiWindow* child = window->DC.ChildWindows[i];
2623  if (child->Active)
2624  AddWindowToSortedBuffer(out_sorted_windows, child);
2625  }
2626  }
2627 }
2628 
2629 static void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_list, ImDrawList* draw_list)
2630 {
2631  if (draw_list->CmdBuffer.empty())
2632  return;
2633 
2634  // Remove trailing command if unused
2635  ImDrawCmd& last_cmd = draw_list->CmdBuffer.back();
2636  if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL)
2637  {
2638  draw_list->CmdBuffer.pop_back();
2639  if (draw_list->CmdBuffer.empty())
2640  return;
2641  }
2642 
2643  // 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.
2644  IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
2645  IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
2646  IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
2647 
2648  // Check that draw_list doesn't use more vertices than indexable in a single draw call (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per window)
2649  // If this assert triggers because you are drawing lots of stuff manually, you can:
2650  // A) Add '#define ImDrawIdx unsigned int' in imconfig.h to set the index size to 4 bytes. You'll need to handle the 4-bytes indices to your renderer.
2651  // For example, the OpenGL example code detect index size at Compile-time by doing:
2652  // 'glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);'
2653  // 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.
2654  // B) 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.
2655  IM_ASSERT(((ImU64)draw_list->_VtxCurrentIdx >> (sizeof(ImDrawIdx)*8)) == 0); // Too many vertices in same ImDrawList. See comment above.
2656 
2657  out_render_list.push_back(draw_list);
2658  GImGui->IO.MetricsRenderVertices += draw_list->VtxBuffer.Size;
2659  GImGui->IO.MetricsRenderIndices += draw_list->IdxBuffer.Size;
2660 }
2661 
2662 static void AddWindowToRenderList(ImVector<ImDrawList*>& out_render_list, ImGuiWindow* window)
2663 {
2664  AddDrawListToRenderList(out_render_list, window->DrawList);
2665  for (int i = 0; i < window->DC.ChildWindows.Size; i++)
2666  {
2667  ImGuiWindow* child = window->DC.ChildWindows[i];
2668  if (!child->Active) // clipped children may have been marked not active
2669  continue;
2670  if ((child->Flags & ImGuiWindowFlags_Popup) && child->HiddenFrames > 0)
2671  continue;
2672  AddWindowToRenderList(out_render_list, child);
2673  }
2674 }
2675 
2676 static void AddWindowToRenderListSelectLayer(ImGuiWindow* window)
2677 {
2678  // FIXME: Generalize this with a proper layering system so e.g. user can draw in specific layers, below text, ..
2679  ImGuiContext& g = *GImGui;
2681  if (window->Flags & ImGuiWindowFlags_Popup)
2682  AddWindowToRenderList(g.RenderDrawLists[1], window);
2683  else if (window->Flags & ImGuiWindowFlags_Tooltip)
2684  AddWindowToRenderList(g.RenderDrawLists[2], window);
2685  else
2686  AddWindowToRenderList(g.RenderDrawLists[0], window);
2687 }
2688 
2689 // 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.
2690 void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
2691 {
2692  ImGuiWindow* window = GetCurrentWindow();
2693  window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
2694  window->ClipRect = window->DrawList->_ClipRectStack.back();
2695 }
2696 
2698 {
2699  ImGuiWindow* window = GetCurrentWindow();
2700  window->DrawList->PopClipRect();
2701  window->ClipRect = window->DrawList->_ClipRectStack.back();
2702 }
2703 
2704 // This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
2706 {
2707  ImGuiContext& g = *GImGui;
2708  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
2709  IM_ASSERT(g.FrameCountEnded != g.FrameCount); // ImGui::EndFrame() called multiple times, or forgot to call ImGui::NewFrame() again
2710 
2711  // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
2712  if (g.IO.ImeSetInputScreenPosFn && ImLengthSqr(g.OsImePosRequest - g.OsImePosSet) > 0.0001f)
2713  {
2716  }
2717 
2718  // Hide implicit "Debug" window if it hasn't been used
2719  IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls
2720  if (g.CurrentWindow && !g.CurrentWindow->Accessed)
2721  g.CurrentWindow->Active = false;
2722  ImGui::End();
2723 
2724  // Click to focus window and start moving (after we're done with all our widgets)
2725  if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0])
2726  {
2727  if (!(g.NavWindow && !g.NavWindow->WasActive && g.NavWindow->Active)) // Unless we just made a popup appear
2728  {
2729  if (g.HoveredRootWindow != NULL)
2730  {
2733  {
2734  g.MovedWindow = g.HoveredWindow;
2737  }
2738  }
2739  else if (g.NavWindow != NULL && GetFrontMostModalRootWindow() == NULL)
2740  {
2741  // Clicking on void disable focus
2742  FocusWindow(NULL);
2743  }
2744  }
2745  }
2746 
2747  // Sort the window list so that all child windows are after their parent
2748  // We cannot do that on FocusWindow() because childs may not exist yet
2751  for (int i = 0; i != g.Windows.Size; i++)
2752  {
2753  ImGuiWindow* window = g.Windows[i];
2754  if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it
2755  continue;
2756  AddWindowToSortedBuffer(g.WindowsSortBuffer, window);
2757  }
2758 
2759  IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); // we done something wrong
2761 
2762  // Clear Input data for next frame
2763  g.IO.MouseWheel = 0.0f;
2764  memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
2765 
2767 }
2768 
2770 {
2771  ImGuiContext& g = *GImGui;
2772  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
2773 
2774  if (g.FrameCountEnded != g.FrameCount)
2775  ImGui::EndFrame();
2777 
2778  // Skip render altogether if alpha is 0.0
2779  // Note that vertex buffers have been created and are wasted, so it is best practice that you don't create windows in the first place, or consistently respond to Begin() returning false.
2780  if (g.Style.Alpha > 0.0f)
2781  {
2782  // Gather windows to render
2784  for (int i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
2785  g.RenderDrawLists[i].resize(0);
2786  for (int i = 0; i != g.Windows.Size; i++)
2787  {
2788  ImGuiWindow* window = g.Windows[i];
2789  if (window->Active && window->HiddenFrames <= 0 && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0)
2790  AddWindowToRenderListSelectLayer(window);
2791  }
2792 
2793  // Flatten layers
2794  int n = g.RenderDrawLists[0].Size;
2795  int flattened_size = n;
2796  for (int i = 1; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
2797  flattened_size += g.RenderDrawLists[i].Size;
2798  g.RenderDrawLists[0].resize(flattened_size);
2799  for (int i = 1; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
2800  {
2801  ImVector<ImDrawList*>& layer = g.RenderDrawLists[i];
2802  if (layer.empty())
2803  continue;
2804  memcpy(&g.RenderDrawLists[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
2805  n += layer.Size;
2806  }
2807 
2808  // Draw software mouse cursor if requested
2809  if (g.IO.MouseDrawCursor)
2810  {
2811  const ImGuiMouseCursorData& cursor_data = g.MouseCursorData[g.MouseCursor];
2812  const ImVec2 pos = g.IO.MousePos - cursor_data.HotOffset;
2813  const ImVec2 size = cursor_data.Size;
2814  const ImTextureID tex_id = g.IO.Fonts->TexID;
2815  g.OverlayDrawList.PushTextureID(tex_id);
2816  g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,48)); // Shadow
2817  g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,48)); // Shadow
2818  g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], IM_COL32(0,0,0,255)); // Black border
2819  g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], IM_COL32(255,255,255,255)); // White fill
2821  }
2822  if (!g.OverlayDrawList.VtxBuffer.empty())
2823  AddDrawListToRenderList(g.RenderDrawLists[0], &g.OverlayDrawList);
2824 
2825  // Setup draw data
2826  g.RenderDrawData.Valid = true;
2827  g.RenderDrawData.CmdLists = (g.RenderDrawLists[0].Size > 0) ? &g.RenderDrawLists[0][0] : NULL;
2831 
2832  // Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData()
2833  if (g.RenderDrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
2835  }
2836 }
2837 
2838 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
2839 {
2840  const char* text_display_end = text;
2841  if (!text_end)
2842  text_end = (const char*)-1;
2843 
2844  while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
2845  text_display_end++;
2846  return text_display_end;
2847 }
2848 
2849 // Pass text data straight to log (without being displayed)
2850 void ImGui::LogText(const char* fmt, ...)
2851 {
2852  ImGuiContext& g = *GImGui;
2853  if (!g.LogEnabled)
2854  return;
2855 
2856  va_list args;
2857  va_start(args, fmt);
2858  if (g.LogFile)
2859  {
2860  vfprintf(g.LogFile, fmt, args);
2861  }
2862  else
2863  {
2864  g.LogClipboard->appendv(fmt, args);
2865  }
2866  va_end(args);
2867 }
2868 
2869 // Internal version that takes a position to decide on newline placement and pad items according to their depth.
2870 // We split text into individual lines to add current tree level padding
2871 static void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL)
2872 {
2873  ImGuiContext& g = *GImGui;
2875 
2876  if (!text_end)
2877  text_end = ImGui::FindRenderedTextEnd(text, text_end);
2878 
2879  const bool log_new_line = ref_pos && (ref_pos->y > window->DC.LogLinePosY + 1);
2880  if (ref_pos)
2881  window->DC.LogLinePosY = ref_pos->y;
2882 
2883  const char* text_remaining = text;
2884  if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth
2885  g.LogStartDepth = window->DC.TreeDepth;
2886  const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth);
2887  for (;;)
2888  {
2889  // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
2890  const char* line_end = text_remaining;
2891  while (line_end < text_end)
2892  if (*line_end == '\n')
2893  break;
2894  else
2895  line_end++;
2896  if (line_end >= text_end)
2897  line_end = NULL;
2898 
2899  const bool is_first_line = (text == text_remaining);
2900  bool is_last_line = false;
2901  if (line_end == NULL)
2902  {
2903  is_last_line = true;
2904  line_end = text_end;
2905  }
2906  if (line_end != NULL && !(is_last_line && (line_end - text_remaining)==0))
2907  {
2908  const int char_count = (int)(line_end - text_remaining);
2909  if (log_new_line || !is_first_line)
2910  ImGui::LogText(IM_NEWLINE "%*s%.*s", tree_depth*4, "", char_count, text_remaining);
2911  else
2912  ImGui::LogText(" %.*s", char_count, text_remaining);
2913  }
2914 
2915  if (is_last_line)
2916  break;
2917  text_remaining = line_end + 1;
2918  }
2919 }
2920 
2921 // Internal ImGui functions to render text
2922 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
2923 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
2924 {
2925  ImGuiContext& g = *GImGui;
2926  ImGuiWindow* window = GetCurrentWindow();
2927 
2928  // Hide anything after a '##' string
2929  const char* text_display_end;
2930  if (hide_text_after_hash)
2931  {
2932  text_display_end = FindRenderedTextEnd(text, text_end);
2933  }
2934  else
2935  {
2936  if (!text_end)
2937  text_end = text + strlen(text); // FIXME-OPT
2938  text_display_end = text_end;
2939  }
2940 
2941  const int text_len = (int)(text_display_end - text);
2942  if (text_len > 0)
2943  {
2944  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
2945  if (g.LogEnabled)
2946  LogRenderedText(&pos, text, text_display_end);
2947  }
2948 }
2949 
2950 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
2951 {
2952  ImGuiContext& g = *GImGui;
2953  ImGuiWindow* window = GetCurrentWindow();
2954 
2955  if (!text_end)
2956  text_end = text + strlen(text); // FIXME-OPT
2957 
2958  const int text_len = (int)(text_end - text);
2959  if (text_len > 0)
2960  {
2961  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
2962  if (g.LogEnabled)
2963  LogRenderedText(&pos, text, text_end);
2964  }
2965 }
2966 
2967 // Default clip_rect uses (pos_min,pos_max)
2968 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
2969 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)
2970 {
2971  // Hide anything after a '##' string
2972  const char* text_display_end = FindRenderedTextEnd(text, text_end);
2973  const int text_len = (int)(text_display_end - text);
2974  if (text_len == 0)
2975  return;
2976 
2977  ImGuiContext& g = *GImGui;
2978  ImGuiWindow* window = GetCurrentWindow();
2979 
2980  // Perform CPU side clipping for single clipped element to avoid using scissor state
2981  ImVec2 pos = pos_min;
2982  const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
2983 
2984  const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
2985  const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
2986  bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
2987  if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
2988  need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
2989 
2990  // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
2991  if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
2992  if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
2993 
2994  // Render
2995  if (need_clipping)
2996  {
2997  ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
2998  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
2999  }
3000  else
3001  {
3002  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
3003  }
3004  if (g.LogEnabled)
3005  LogRenderedText(&pos, text, text_display_end);
3006 }
3007 
3008 // Render a rectangle shaped with optional rounding and borders
3009 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
3010 {
3011  ImGuiWindow* window = GetCurrentWindow();
3012 
3013  window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
3014  if (border && (window->Flags & ImGuiWindowFlags_ShowBorders))
3015  {
3016  window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding);
3017  window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding);
3018  }
3019 }
3020 
3021 void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
3022 {
3023  ImGuiWindow* window = GetCurrentWindow();
3024  if (window->Flags & ImGuiWindowFlags_ShowBorders)
3025  {
3026  window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding);
3027  window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding);
3028  }
3029 }
3030 
3031 // Render a triangle to denote expanded/collapsed state
3032 void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool is_open, float scale)
3033 {
3034  ImGuiContext& g = *GImGui;
3035  ImGuiWindow* window = GetCurrentWindow();
3036 
3037  const float h = g.FontSize * 1.00f;
3038  const float r = h * 0.40f * scale;
3039  ImVec2 center = p_min + ImVec2(h*0.50f, h*0.50f*scale);
3040 
3041  ImVec2 a, b, c;
3042  if (is_open)
3043  {
3044  center.y -= r*0.25f;
3045  a = center + ImVec2(0,1)*r;
3046  b = center + ImVec2(-0.866f,-0.5f)*r;
3047  c = center + ImVec2(0.866f,-0.5f)*r;
3048  }
3049  else
3050  {
3051  a = center + ImVec2(1,0)*r;
3052  b = center + ImVec2(-0.500f,0.866f)*r;
3053  c = center + ImVec2(-0.500f,-0.866f)*r;
3054  }
3055 
3057 }
3058 
3060 {
3061  ImGuiWindow* window = GetCurrentWindow();
3062  window->DrawList->AddCircleFilled(pos, GImGui->FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8);
3063 }
3064 
3066 {
3067  ImGuiContext& g = *GImGui;
3068  ImGuiWindow* window = GetCurrentWindow();
3069  float start_x = (float)(int)(g.FontSize * 0.307f + 0.5f);
3070  float rem_third = (float)(int)((g.FontSize - start_x) / 3.0f);
3071  float bx = pos.x + 0.5f + start_x + rem_third;
3072  float by = pos.y - 1.0f + (float)(int)(g.Font->Ascent * (g.FontSize / g.Font->FontSize) + 0.5f) + (float)(int)(g.Font->DisplayOffset.y);
3073  window->DrawList->PathLineTo(ImVec2(bx - rem_third, by - rem_third));
3074  window->DrawList->PathLineTo(ImVec2(bx, by));
3075  window->DrawList->PathLineTo(ImVec2(bx + rem_third*2, by - rem_third*2));
3076  window->DrawList->PathStroke(col, false);
3077 }
3078 
3079 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
3080 // CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize)
3081 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
3082 {
3083  ImGuiContext& g = *GImGui;
3084 
3085  const char* text_display_end;
3086  if (hide_text_after_double_hash)
3087  text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
3088  else
3089  text_display_end = text_end;
3090 
3091  ImFont* font = g.Font;
3092  const float font_size = g.FontSize;
3093  if (text == text_display_end)
3094  return ImVec2(0.0f, font_size);
3095  ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
3096 
3097  // Cancel out character spacing for the last character of a line (it is baked into glyph->AdvanceX field)
3098  const float font_scale = font_size / font->FontSize;
3099  const float character_spacing_x = 1.0f * font_scale;
3100  if (text_size.x > 0.0f)
3101  text_size.x -= character_spacing_x;
3102  text_size.x = (float)(int)(text_size.x + 0.95f);
3103 
3104  return text_size;
3105 }
3106 
3107 // Helper to calculate coarse clipping of large list of evenly sized items.
3108 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
3109 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
3110 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
3111 {
3112  ImGuiContext& g = *GImGui;
3113  ImGuiWindow* window = GetCurrentWindowRead();
3114  if (g.LogEnabled)
3115  {
3116  // If logging is active, do not perform any clipping
3117  *out_items_display_start = 0;
3118  *out_items_display_end = items_count;
3119  return;
3120  }
3121  if (window->SkipItems)
3122  {
3123  *out_items_display_start = *out_items_display_end = 0;
3124  return;
3125  }
3126 
3127  const ImVec2 pos = window->DC.CursorPos;
3128  int start = (int)((window->ClipRect.Min.y - pos.y) / items_height);
3129  int end = (int)((window->ClipRect.Max.y - pos.y) / items_height);
3130  start = ImClamp(start, 0, items_count);
3131  end = ImClamp(end + 1, start, items_count);
3132  *out_items_display_start = start;
3133  *out_items_display_end = end;
3134 }
3135 
3136 // Find window given position, search front-to-back
3137 // 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.
3138 static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs)
3139 {
3140  ImGuiContext& g = *GImGui;
3141  for (int i = g.Windows.Size-1; i >= 0; i--)
3142  {
3143  ImGuiWindow* window = g.Windows[i];
3144  if (!window->Active)
3145  continue;
3146  if (window->Flags & ImGuiWindowFlags_NoInputs)
3147  continue;
3148  if (excluding_childs && (window->Flags & ImGuiWindowFlags_ChildWindow) != 0)
3149  continue;
3150 
3151  // Using the clipped AABB so a child window will typically be clipped by its parent.
3153  if (bb.Contains(pos))
3154  return window;
3155  }
3156  return NULL;
3157 }
3158 
3159 // Test if mouse cursor is hovering given rectangle
3160 // NB- Rectangle is clipped by our current clip setting
3161 // NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
3162 bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
3163 {
3164  ImGuiContext& g = *GImGui;
3165  ImGuiWindow* window = GetCurrentWindowRead();
3166 
3167  // Clip
3168  ImRect rect_clipped(r_min, r_max);
3169  if (clip)
3170  rect_clipped.ClipWith(window->ClipRect);
3171 
3172  // Expand for touch input
3173  const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
3174  return rect_for_touch.Contains(g.IO.MousePos);
3175 }
3176 
3178 {
3179  ImGuiContext& g = *GImGui;
3180  return g.HoveredWindow != NULL;
3181 }
3182 
3183 static bool IsKeyPressedMap(ImGuiKey key, bool repeat)
3184 {
3185  const int key_index = GImGui->IO.KeyMap[key];
3186  return (key_index >= 0) ? ImGui::IsKeyPressed(key_index, repeat) : false;
3187 }
3188 
3190 {
3191  IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
3192  return GImGui->IO.KeyMap[imgui_key];
3193 }
3194 
3195 // Note that imgui doesn't know the semantic of each entry of io.KeyDown[]. Use your own indices/enums according to how your backend/engine stored them into KeyDown[]!
3196 bool ImGui::IsKeyDown(int user_key_index)
3197 {
3198  if (user_key_index < 0) return false;
3199  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown));
3200  return GImGui->IO.KeysDown[user_key_index];
3201 }
3202 
3203 int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
3204 {
3205  if (t == 0.0f)
3206  return 1;
3207  if (t <= repeat_delay || repeat_rate <= 0.0f)
3208  return 0;
3209  const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate);
3210  return (count > 0) ? count : 0;
3211 }
3212 
3213 int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
3214 {
3215  ImGuiContext& g = *GImGui;
3216  if (key_index < 0) return false;
3217  IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
3218  const float t = g.IO.KeysDownDuration[key_index];
3219  return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate);
3220 }
3221 
3222 bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
3223 {
3224  ImGuiContext& g = *GImGui;
3225  if (user_key_index < 0) return false;
3226  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
3227  const float t = g.IO.KeysDownDuration[user_key_index];
3228  if (t == 0.0f)
3229  return true;
3230  if (repeat && t > g.IO.KeyRepeatDelay)
3231  return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
3232  return false;
3233 }
3234 
3235 bool ImGui::IsKeyReleased(int user_key_index)
3236 {
3237  ImGuiContext& g = *GImGui;
3238  if (user_key_index < 0) return false;
3239  IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
3240  if (g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index])
3241  return true;
3242  return false;
3243 }
3244 
3245 bool ImGui::IsMouseDown(int button)
3246 {
3247  ImGuiContext& g = *GImGui;
3248  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3249  return g.IO.MouseDown[button];
3250 }
3251 
3252 bool ImGui::IsMouseClicked(int button, bool repeat)
3253 {
3254  ImGuiContext& g = *GImGui;
3255  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3256  const float t = g.IO.MouseDownDuration[button];
3257  if (t == 0.0f)
3258  return true;
3259 
3260  if (repeat && t > g.IO.KeyRepeatDelay)
3261  {
3262  float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate;
3263  if ((fmodf(t - delay, rate) > rate*0.5f) != (fmodf(t - delay - g.IO.DeltaTime, rate) > rate*0.5f))
3264  return true;
3265  }
3266 
3267  return false;
3268 }
3269 
3270 bool ImGui::IsMouseReleased(int button)
3271 {
3272  ImGuiContext& g = *GImGui;
3273  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3274  return g.IO.MouseReleased[button];
3275 }
3276 
3278 {
3279  ImGuiContext& g = *GImGui;
3280  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3281  return g.IO.MouseDoubleClicked[button];
3282 }
3283 
3284 bool ImGui::IsMouseDragging(int button, float lock_threshold)
3285 {
3286  ImGuiContext& g = *GImGui;
3287  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3288  if (!g.IO.MouseDown[button])
3289  return false;
3290  if (lock_threshold < 0.0f)
3291  lock_threshold = g.IO.MouseDragThreshold;
3292  return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
3293 }
3294 
3296 {
3297  return GImGui->IO.MousePos;
3298 }
3299 
3300 // NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
3302 {
3303  ImGuiContext& g = *GImGui;
3304  if (g.CurrentPopupStack.Size > 0)
3305  return g.OpenPopupStack[g.CurrentPopupStack.Size-1].MousePosOnOpen;
3306  return g.IO.MousePos;
3307 }
3308 
3309 // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position
3310 bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
3311 {
3312  if (mouse_pos == NULL)
3313  mouse_pos = &GImGui->IO.MousePos;
3314  const float MOUSE_INVALID = -256000.0f;
3315  return mouse_pos->x >= MOUSE_INVALID && mouse_pos->y >= MOUSE_INVALID;
3316 }
3317 
3318 ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
3319 {
3320  ImGuiContext& g = *GImGui;
3321  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3322  if (lock_threshold < 0.0f)
3323  lock_threshold = g.IO.MouseDragThreshold;
3324  if (g.IO.MouseDown[button])
3325  if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
3326  return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment).
3327  return ImVec2(0.0f, 0.0f);
3328 }
3329 
3331 {
3332  ImGuiContext& g = *GImGui;
3333  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3334  // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
3335  g.IO.MouseClickedPos[button] = g.IO.MousePos;
3336 }
3337 
3339 {
3340  return GImGui->MouseCursor;
3341 }
3342 
3344 {
3345  GImGui->MouseCursor = cursor_type;
3346 }
3347 
3349 {
3350  GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
3351 }
3352 
3353 void ImGui::CaptureMouseFromApp(bool capture)
3354 {
3355  GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
3356 }
3357 
3359 {
3360  ImGuiContext& g = *GImGui;
3361  if (g.ActiveId)
3362  {
3363  ImGuiWindow* window = GetCurrentWindowRead();
3364  return g.ActiveId == window->DC.LastItemId;
3365  }
3366  return false;
3367 }
3368 
3369 bool ImGui::IsItemClicked(int mouse_button)
3370 {
3371  return IsMouseClicked(mouse_button) && IsItemHovered();
3372 }
3373 
3375 {
3376  return GImGui->HoveredId != 0 || GImGui->HoveredIdPreviousFrame != 0;
3377 }
3378 
3380 {
3381  return GImGui->ActiveId != 0;
3382 }
3383 
3385 {
3386  ImGuiWindow* window = GetCurrentWindowRead();
3387  return window->ClipRect.Overlaps(window->DC.LastItemRect);
3388 }
3389 
3390 // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
3392 {
3393  ImGuiContext& g = *GImGui;
3394  if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
3395  g.HoveredIdAllowOverlap = true;
3396  if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
3397  g.ActiveIdAllowOverlap = true;
3398 }
3399 
3401 {
3402  ImGuiWindow* window = GetCurrentWindowRead();
3403  return window->DC.LastItemRect.Min;
3404 }
3405 
3407 {
3408  ImGuiWindow* window = GetCurrentWindowRead();
3409  return window->DC.LastItemRect.Max;
3410 }
3411 
3413 {
3414  ImGuiWindow* window = GetCurrentWindowRead();
3415  return window->DC.LastItemRect.GetSize();
3416 }
3417 
3418 ImVec2 ImGui::CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge, float outward)
3419 {
3420  ImGuiWindow* window = GetCurrentWindowRead();
3421  ImRect rect = window->DC.LastItemRect;
3422  rect.Expand(outward);
3423  return rect.GetClosestPoint(pos, on_edge);
3424 }
3425 
3426 static ImRect GetVisibleRect()
3427 {
3428  ImGuiContext& g = *GImGui;
3431  return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
3432 }
3433 
3434 // Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first.
3435 static void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip)
3436 {
3437  ImGuiContext& g = *GImGui;
3438  char window_name[16];
3439  ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip%02d", g.TooltipOverrideCount);
3440  if (override_previous_tooltip)
3441  if (ImGuiWindow* window = ImGui::FindWindowByName(window_name))
3442  if (window->Active)
3443  {
3444  // Hide previous tooltips. We can't easily "reset" the content of a window so we create a new one.
3445  window->HiddenFrames = 1;
3446  ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip%02d", ++g.TooltipOverrideCount);
3447  }
3449  ImGui::Begin(window_name, NULL, flags | extra_flags);
3450 }
3451 
3452 void ImGui::SetTooltipV(const char* fmt, va_list args)
3453 {
3454  BeginTooltipEx(0, true);
3455  TextV(fmt, args);
3456  EndTooltip();
3457 }
3458 
3459 void ImGui::SetTooltip(const char* fmt, ...)
3460 {
3461  va_list args;
3462  va_start(args, fmt);
3463  SetTooltipV(fmt, args);
3464  va_end(args);
3465 }
3466 
3468 {
3469  BeginTooltipEx(0, false);
3470 }
3471 
3473 {
3474  IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls
3475  ImGui::End();
3476 }
3477 
3478 // Mark popup as open (toggle toward open state).
3479 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
3480 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
3481 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
3482 void ImGui::OpenPopupEx(ImGuiID id, bool reopen_existing)
3483 {
3484  ImGuiContext& g = *GImGui;
3485  ImGuiWindow* window = g.CurrentWindow;
3486  int current_stack_size = g.CurrentPopupStack.Size;
3487  ImGuiPopupRef popup_ref = ImGuiPopupRef(id, window, window->GetID("##menus"), g.IO.MousePos); // Tagged as new ref because constructor sets Window to NULL (we are passing the ParentWindow info here)
3488  if (g.OpenPopupStack.Size < current_stack_size + 1)
3489  g.OpenPopupStack.push_back(popup_ref);
3490  else if (reopen_existing || g.OpenPopupStack[current_stack_size].PopupId != id)
3491  {
3492  g.OpenPopupStack.resize(current_stack_size+1);
3493  g.OpenPopupStack[current_stack_size] = popup_ref;
3494  }
3495 }
3496 
3497 void ImGui::OpenPopup(const char* str_id)
3498 {
3499  ImGuiContext& g = *GImGui;
3500  OpenPopupEx(g.CurrentWindow->GetID(str_id), false);
3501 }
3502 
3503 static void CloseInactivePopups()
3504 {
3505  ImGuiContext& g = *GImGui;
3506  if (g.OpenPopupStack.empty())
3507  return;
3508 
3509  // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
3510  // Don't close our own child popup windows
3511  int n = 0;
3512  if (g.NavWindow)
3513  {
3514  for (n = 0; n < g.OpenPopupStack.Size; n++)
3515  {
3516  ImGuiPopupRef& popup = g.OpenPopupStack[n];
3517  if (!popup.Window)
3518  continue;
3519  IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
3521  continue;
3522 
3523  bool has_focus = false;
3524  for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++)
3525  has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == g.NavWindow->RootWindow);
3526  if (!has_focus)
3527  break;
3528  }
3529  }
3530  if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a useful breakpoint on the line below
3531  g.OpenPopupStack.resize(n);
3532 }
3533 
3534 static ImGuiWindow* GetFrontMostModalRootWindow()
3535 {
3536  ImGuiContext& g = *GImGui;
3537  for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
3538  if (ImGuiWindow* front_most_popup = g.OpenPopupStack.Data[n].Window)
3539  if (front_most_popup->Flags & ImGuiWindowFlags_Modal)
3540  return front_most_popup;
3541  return NULL;
3542 }
3543 
3544 static void ClosePopupToLevel(int remaining)
3545 {
3546  ImGuiContext& g = *GImGui;
3547  if (remaining > 0)
3548  ImGui::FocusWindow(g.OpenPopupStack[remaining-1].Window);
3549  else
3550  ImGui::FocusWindow(g.OpenPopupStack[0].ParentWindow);
3551  g.OpenPopupStack.resize(remaining);
3552 }
3553 
3555 {
3556  if (!IsPopupOpen(id))
3557  return;
3558  ImGuiContext& g = *GImGui;
3559  ClosePopupToLevel(g.OpenPopupStack.Size - 1);
3560 }
3561 
3562 // Close the popup we have begin-ed into.
3564 {
3565  ImGuiContext& g = *GImGui;
3566  int popup_idx = g.CurrentPopupStack.Size - 1;
3567  if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
3568  return;
3569  while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
3570  popup_idx--;
3571  ClosePopupToLevel(popup_idx);
3572 }
3573 
3574 static inline void ClearSetNextWindowData()
3575 {
3576  // FIXME-OPT
3577  ImGuiContext& g = *GImGui;
3580 }
3581 
3583 {
3584  ImGuiContext& g = *GImGui;
3585  ImGuiWindow* window = g.CurrentWindow;
3586  if (!IsPopupOpen(id))
3587  {
3588  ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
3589  return false;
3590  }
3591 
3594 
3595  char name[20];
3596  if (flags & ImGuiWindowFlags_ChildMenu)
3597  ImFormatString(name, IM_ARRAYSIZE(name), "##menu_%d", g.CurrentPopupStack.Size); // Recycle windows based on depth
3598  else
3599  ImFormatString(name, IM_ARRAYSIZE(name), "##popup_%08x", id); // Not recycling, so we can close/open during the same frame
3600 
3601  bool is_open = Begin(name, NULL, flags);
3602  if (!(window->Flags & ImGuiWindowFlags_ShowBorders))
3604  if (!is_open) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
3605  EndPopup();
3606 
3607  return is_open;
3608 }
3609 
3610 bool ImGui::BeginPopup(const char* str_id)
3611 {
3612  ImGuiContext& g = *GImGui;
3613  if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance
3614  {
3615  ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
3616  return false;
3617  }
3619 }
3620 
3622 {
3623  ImGuiContext& g = *GImGui;
3624  return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == id;
3625 }
3626 
3627 bool ImGui::IsPopupOpen(const char* str_id)
3628 {
3629  ImGuiContext& g = *GImGui;
3631 }
3632 
3633 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags extra_flags)
3634 {
3635  ImGuiContext& g = *GImGui;
3636  ImGuiWindow* window = g.CurrentWindow;
3637  const ImGuiID id = window->GetID(name);
3638  if (!IsPopupOpen(id))
3639  {
3640  ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
3641  return false;
3642  }
3643 
3644  // Center modal windows by default
3645  if ((window->SetWindowPosAllowFlags & g.SetNextWindowPosCond) == 0)
3646  SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
3647 
3649  bool is_open = Begin(name, p_open, flags);
3650  if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
3651  {
3652  EndPopup();
3653  if (is_open)
3654  ClosePopup(id);
3655  return false;
3656  }
3657 
3658  return is_open;
3659 }
3660 
3662 {
3663  ImGuiWindow* window = GetCurrentWindow();
3664  IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
3665  IM_ASSERT(GImGui->CurrentPopupStack.Size > 0);
3666  End();
3667  if (!(window->Flags & ImGuiWindowFlags_Modal))
3668  PopStyleVar();
3669 }
3670 
3671 // This is a helper to handle the most simple case of associating one named popup to one given widget.
3672 // 1. If you have many possible popups (for different "instances" of a same widget, or for wholly different widgets), you may be better off handling
3673 // this yourself so you can store data relative to the widget that opened the popup instead of choosing different popup identifiers.
3674 // 2. If you want right-clicking on the same item to reopen the popup at new location, use the same code replacing IsItemHovered() with IsItemRectHovered()
3675 // and passing true to the OpenPopupEx().
3676 // Because: hovering an item in a window below the popup won't normally trigger is hovering behavior/coloring. The pattern of ignoring the fact that
3677 // the item can be interacted with (because it is blocked by the active popup) may useful in some situation when e.g. large canvas as one item, content of menu
3678 // driven by click position.
3679 bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
3680 {
3681  if (IsItemHovered() && IsMouseClicked(mouse_button))
3682  OpenPopupEx(GImGui->CurrentWindow->GetID(str_id), false);
3683  return BeginPopup(str_id);
3684 }
3685 
3686 bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items)
3687 {
3688  if (!str_id)
3689  str_id = "window_context";
3690  if (IsWindowRectHovered() && IsMouseClicked(mouse_button))
3691  if (also_over_items || !IsAnyItemHovered())
3692  OpenPopupEx(GImGui->CurrentWindow->GetID(str_id), true);
3693  return BeginPopup(str_id);
3694 }
3695 
3696 bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
3697 {
3698  if (!str_id)
3699  str_id = "void_context";
3700  if (!IsAnyWindowHovered() && IsMouseClicked(mouse_button))
3701  OpenPopupEx(GImGui->CurrentWindow->GetID(str_id), true);
3702  return BeginPopup(str_id);
3703 }
3704 
3705 static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
3706 {
3707  ImGuiWindow* parent_window = ImGui::GetCurrentWindow();
3709 
3710  const ImVec2 content_avail = ImGui::GetContentRegionAvail();
3711  ImVec2 size = ImFloor(size_arg);
3712  const int auto_fit_axises = ((size.x == 0.0f) ? 0x01 : 0x00) | ((size.y == 0.0f) ? 0x02 : 0x00);
3713  if (size.x <= 0.0f)
3714  size.x = ImMax(content_avail.x, 4.0f) - fabsf(size.x); // Arbitrary minimum zero-ish child size of 4.0f (0.0f causing too much issues)
3715  if (size.y <= 0.0f)
3716  size.y = ImMax(content_avail.y, 4.0f) - fabsf(size.y);
3717  if (border)
3719  flags |= extra_flags;
3720 
3721  char title[256];
3722  if (name)
3723  ImFormatString(title, IM_ARRAYSIZE(title), "%s.%s.%08X", parent_window->Name, name, id);
3724  else
3725  ImFormatString(title, IM_ARRAYSIZE(title), "%s.%08X", parent_window->Name, id);
3726 
3727  bool ret = ImGui::Begin(title, NULL, size, -1.0f, flags);
3728  ImGuiWindow* child_window = ImGui::GetCurrentWindow();
3729  child_window->AutoFitChildAxises = auto_fit_axises;
3730  if (!(parent_window->Flags & ImGuiWindowFlags_ShowBorders))
3731  child_window->Flags &= ~ImGuiWindowFlags_ShowBorders;
3732 
3733  return ret;
3734 }
3735 
3736 bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
3737 {
3738  ImGuiWindow* window = GetCurrentWindow();
3739  return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
3740 }
3741 
3742 bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
3743 {
3744  return BeginChildEx(NULL, id, size_arg, border, extra_flags);
3745 }
3746 
3748 {
3749  ImGuiWindow* window = GetCurrentWindow();
3750 
3751  IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss
3752  if ((window->Flags & ImGuiWindowFlags_ComboBox) || window->BeginCount > 1)
3753  {
3754  ImGui::End();
3755  }
3756  else
3757  {
3758  // 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.
3759  ImVec2 sz = GetWindowSize();
3760  if (window->AutoFitChildAxises & 0x01) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
3761  sz.x = ImMax(4.0f, sz.x);
3762  if (window->AutoFitChildAxises & 0x02)
3763  sz.y = ImMax(4.0f, sz.y);
3764  ImGui::End();
3765 
3766  ImGuiWindow* parent_window = GetCurrentWindow();
3767  ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
3768  ItemSize(sz);
3769  ItemAdd(bb, NULL);
3770  }
3771 }
3772 
3773 // Helper to create a child window / scrolling region that looks like a normal widget frame.
3774 bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)
3775 {
3776  ImGuiContext& g = *GImGui;
3777  const ImGuiStyle& style = g.Style;
3782 }
3783 
3785 {
3786  EndChild();
3787  PopStyleVar(2);
3788  PopStyleColor();
3789 }
3790 
3791 // Save and compare stack sizes on Begin()/End() to detect usage errors
3792 static void CheckStacksSize(ImGuiWindow* window, bool write)
3793 {
3794  // 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)
3795  ImGuiContext& g = *GImGui;
3796  int* p_backup = &window->DC.StackSizesBackup[0];
3797  { 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()
3798  { 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()
3799  { 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()
3800  { 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()
3801  { 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()
3802  { 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()
3803  IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
3804 }
3805 
3806 static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& r_inner)
3807 {
3808  const ImGuiStyle& style = GImGui->Style;
3809 
3810  // Clamp into visible area while not overlapping the cursor. Safety padding is optional if our popup size won't fit without it.
3811  ImVec2 safe_padding = style.DisplaySafeAreaPadding;
3812  ImRect r_outer(GetVisibleRect());
3813  r_outer.Expand(ImVec2((size.x - r_outer.GetWidth() > safe_padding.x*2) ? -safe_padding.x : 0.0f, (size.y - r_outer.GetHeight() > safe_padding.y*2) ? -safe_padding.y : 0.0f));
3814  ImVec2 base_pos_clamped = ImClamp(base_pos, r_outer.Min, r_outer.Max - size);
3815 
3816  for (int n = (*last_dir != -1) ? -1 : 0; n < 4; n++) // Last, Right, down, up, left. (Favor last used direction).
3817  {
3818  const int dir = (n == -1) ? *last_dir : n;
3819  ImRect rect(dir == 0 ? r_inner.Max.x : r_outer.Min.x, dir == 1 ? r_inner.Max.y : r_outer.Min.y, dir == 3 ? r_inner.Min.x : r_outer.Max.x, dir == 2 ? r_inner.Min.y : r_outer.Max.y);
3820  if (rect.GetWidth() < size.x || rect.GetHeight() < size.y)
3821  continue;
3822  *last_dir = dir;
3823  return ImVec2(dir == 0 ? r_inner.Max.x : dir == 3 ? r_inner.Min.x - size.x : base_pos_clamped.x, dir == 1 ? r_inner.Max.y : dir == 2 ? r_inner.Min.y - size.y : base_pos_clamped.y);
3824  }
3825 
3826  // Fallback, try to keep within display
3827  *last_dir = -1;
3828  ImVec2 pos = base_pos;
3829  pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
3830  pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
3831  return pos;
3832 }
3833 
3835 {
3836  // FIXME-OPT: Store sorted hashes -> pointers so we can do a bissection in a contiguous block
3837  ImGuiContext& g = *GImGui;
3838  ImGuiID id = ImHash(name, 0);
3839  for (int i = 0; i < g.Windows.Size; i++)
3840  if (g.Windows[i]->ID == id)
3841  return g.Windows[i];
3842  return NULL;
3843 }
3844 
3845 static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags)
3846 {
3847  ImGuiContext& g = *GImGui;
3848 
3849  // Create window the first time
3850  ImGuiWindow* window = (ImGuiWindow*)ImGui::MemAlloc(sizeof(ImGuiWindow));
3851  IM_PLACEMENT_NEW(window) ImGuiWindow(name);
3852  window->Flags = flags;
3853 
3855  {
3856  // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
3857  window->Size = window->SizeFull = size;
3858  }
3859  else
3860  {
3861  // Retrieve settings from .ini file
3862  // Use SetWindowPos() or SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
3863  window->PosFloat = ImVec2(60, 60);
3864  window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y);
3865 
3866  ImGuiIniData* settings = FindWindowSettings(name);
3867  if (!settings)
3868  {
3869  settings = AddWindowSettings(name);
3870  }
3871  else
3872  {
3876  }
3877 
3878  if (settings->Pos.x != FLT_MAX)
3879  {
3880  window->PosFloat = settings->Pos;
3881  window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y);
3882  window->Collapsed = settings->Collapsed;
3883  }
3884 
3885  if (ImLengthSqr(settings->Size) > 0.00001f)
3886  size = settings->Size;
3887  window->Size = window->SizeFull = size;
3888  }
3889 
3890  if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
3891  {
3892  window->AutoFitFramesX = window->AutoFitFramesY = 2;
3893  window->AutoFitOnlyGrows = false;
3894  }
3895  else
3896  {
3897  if (window->Size.x <= 0.0f)
3898  window->AutoFitFramesX = 2;
3899  if (window->Size.y <= 0.0f)
3900  window->AutoFitFramesY = 2;
3901  window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
3902  }
3903 
3905  g.Windows.insert(g.Windows.begin(), window); // Quite slow but rare and only once
3906  else
3907  g.Windows.push_back(window);
3908  return window;
3909 }
3910 
3911 static ImVec2 CalcSizeFullWithConstraint(ImGuiWindow* window, ImVec2 new_size)
3912 {
3913  ImGuiContext& g = *GImGui;
3915  {
3916  // Using -1,-1 on either X/Y axis to preserve the current size.
3918  new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
3919  new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
3921  {
3924  data.Pos = window->Pos;
3925  data.CurrentSize = window->SizeFull;
3926  data.DesiredSize = new_size;
3928  new_size = data.DesiredSize;
3929  }
3930  }
3932  new_size = ImMax(new_size, g.Style.WindowMinSize);
3933  return new_size;
3934 }
3935 
3936 static ImVec2 CalcSizeAutoFit(ImGuiWindow* window)
3937 {
3938  ImGuiContext& g = *GImGui;
3939  ImGuiStyle& style = g.Style;
3940  ImGuiWindowFlags flags = window->Flags;
3941  ImVec2 size_auto_fit;
3942  if ((flags & ImGuiWindowFlags_Tooltip) != 0)
3943  {
3944  // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose.
3945  size_auto_fit = window->SizeContents + window->WindowPadding - ImVec2(0.0f, style.ItemSpacing.y);
3946  }
3947  else
3948  {
3949  // Handling case of auto fit window not fitting on the screen (on either axis): we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than DisplaySize-WindowPadding.
3950  size_auto_fit = ImClamp(window->SizeContents + window->WindowPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - g.Style.DisplaySafeAreaPadding));
3951  ImVec2 size_auto_fit_after_constraint = CalcSizeFullWithConstraint(window, size_auto_fit);
3952  if (size_auto_fit_after_constraint.x < window->SizeContents.x && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar))
3953  size_auto_fit.y += style.ScrollbarSize;
3954  if (size_auto_fit_after_constraint.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar))
3955  size_auto_fit.x += style.ScrollbarSize * 2.0f;
3956  size_auto_fit.y = ImMax(size_auto_fit.y - style.ItemSpacing.y, 0.0f);
3957  }
3958  return size_auto_fit;
3959 }
3960 
3961 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
3962 {
3963  ImVec2 scroll = window->Scroll;
3964  float cr_x = window->ScrollTargetCenterRatio.x;
3965  float cr_y = window->ScrollTargetCenterRatio.y;
3966  if (window->ScrollTarget.x < FLT_MAX)
3967  scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
3968  if (window->ScrollTarget.y < FLT_MAX)
3969  scroll.y = window->ScrollTarget.y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y);
3970  scroll = ImMax(scroll, ImVec2(0.0f, 0.0f));
3971  if (!window->Collapsed && !window->SkipItems)
3972  {
3973  scroll.x = ImMin(scroll.x, ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x))); // == GetScrollMaxX for that window
3974  scroll.y = ImMin(scroll.y, ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y))); // == GetScrollMaxY for that window
3975  }
3976  return scroll;
3977 }
3978 
3979 // Push a new ImGui window to add widgets to.
3980 // - 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.
3981 // - Begin/End can be called multiple times during the frame with the same window name to append content.
3982 // - 'size_on_first_use' for a regular window denote the initial size for first-time creation (no saved data) and isn't that useful. Use SetNextWindowSize() prior to calling Begin() for more flexible window manipulation.
3983 // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
3984 // You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.
3985 // - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.
3986 // - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.
3987 // - Passing non-zero 'size' is roughly equivalent to calling SetNextWindowSize(size, ImGuiCond_FirstUseEver) prior to calling Begin().
3988 bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
3989 {
3990  return ImGui::Begin(name, p_open, ImVec2(0.f, 0.f), -1.0f, flags);
3991 }
3992 
3993 bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha, ImGuiWindowFlags flags)
3994 {
3995  ImGuiContext& g = *GImGui;
3996  const ImGuiStyle& style = g.Style;
3997  IM_ASSERT(name != NULL); // Window name required
3998  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
3999  IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
4000 
4001  if (flags & ImGuiWindowFlags_NoInputs)
4003 
4004  // Find or create
4005  bool window_is_new = false;
4006  ImGuiWindow* window = FindWindowByName(name);
4007  if (!window)
4008  {
4009  window = CreateNewWindow(name, size_on_first_use, flags);
4010  window_is_new = true;
4011  }
4012 
4013  const int current_frame = g.FrameCount;
4014  const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
4015  if (first_begin_of_the_frame)
4016  window->Flags = (ImGuiWindowFlags)flags;
4017  else
4018  flags = window->Flags;
4019 
4020  // Add to stack
4021  ImGuiWindow* parent_window = !g.CurrentWindowStack.empty() ? g.CurrentWindowStack.back() : NULL;
4022  g.CurrentWindowStack.push_back(window);
4023  SetCurrentWindow(window);
4024  CheckStacksSize(window, true);
4025  IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
4026 
4027  bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
4028  if (flags & ImGuiWindowFlags_Popup)
4029  {
4031  window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
4032  window_just_activated_by_user |= (window != popup_ref.Window);
4033  popup_ref.Window = window;
4034  g.CurrentPopupStack.push_back(popup_ref);
4035  window->PopupId = popup_ref.PopupId;
4036  }
4037 
4038  const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFrames == 1);
4039  window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
4040 
4041  // Process SetNextWindow***() calls
4042  bool window_pos_set_by_api = false, window_size_set_by_api = false;
4043  if (g.SetNextWindowPosCond)
4044  {
4045  if (window->Appearing)
4047  window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.SetNextWindowPosCond) != 0;
4048  if (window_pos_set_by_api && ImLengthSqr(g.SetNextWindowPosPivot) > 0.00001f)
4049  {
4050  // May be processed on the next frame if this is our first frame and we are measuring size
4051  // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
4055  }
4056  else
4057  {
4058  SetWindowPos(window, g.SetNextWindowPosVal, g.SetNextWindowPosCond);
4059  }
4060  g.SetNextWindowPosCond = 0;
4061  }
4062  if (g.SetNextWindowSizeCond)
4063  {
4064  if (window->Appearing)
4066  window_size_set_by_api = (window->SetWindowSizeAllowFlags & g.SetNextWindowSizeCond) != 0;
4067  SetWindowSize(window, g.SetNextWindowSizeVal, g.SetNextWindowSizeCond);
4068  g.SetNextWindowSizeCond = 0;
4069  }
4071  {
4074  }
4075  else if (first_begin_of_the_frame)
4076  {
4077  window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
4078  }
4080  {
4081  if (window->Appearing)
4083  SetWindowCollapsed(window, g.SetNextWindowCollapsedVal, g.SetNextWindowCollapsedCond);
4085  }
4086  if (g.SetNextWindowFocus)
4087  {
4088  SetWindowFocus();
4089  g.SetNextWindowFocus = false;
4090  }
4091 
4092  // Update known root window (if we are a child window, otherwise window == window->RootWindow)
4093  int root_idx, root_non_popup_idx;
4094  for (root_idx = g.CurrentWindowStack.Size - 1; root_idx > 0; root_idx--)
4095  if (!(g.CurrentWindowStack[root_idx]->Flags & ImGuiWindowFlags_ChildWindow))
4096  break;
4097  for (root_non_popup_idx = root_idx; root_non_popup_idx > 0; root_non_popup_idx--)
4098  if (!(g.CurrentWindowStack[root_non_popup_idx]->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) || (g.CurrentWindowStack[root_non_popup_idx]->Flags & ImGuiWindowFlags_Modal))
4099  break;
4100  window->ParentWindow = parent_window;
4101  window->RootWindow = g.CurrentWindowStack[root_idx];
4102  window->RootNonPopupWindow = g.CurrentWindowStack[root_non_popup_idx]; // Used to display TitleBgActive color and for selecting which window to use for NavWindowing
4103 
4104  // When reusing window again multiple times a frame, just append content (don't need to setup again)
4105  if (first_begin_of_the_frame)
4106  {
4107  window->Active = true;
4108  window->OrderWithinParent = 0;
4109  window->BeginCount = 0;
4110  window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
4111  window->LastFrameActive = current_frame;
4112  window->IDStack.resize(1);
4113 
4114  // Clear draw list, setup texture, outer clipping rectangle
4115  window->DrawList->Clear();
4117  ImRect fullscreen_rect(GetVisibleRect());
4118  if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_ComboBox|ImGuiWindowFlags_Popup)))
4119  PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true);
4120  else
4121  PushClipRect(fullscreen_rect.Min, fullscreen_rect.Max, true);
4122 
4123  if (window_just_activated_by_user)
4124  {
4125  // Popup first latch mouse position, will position itself when it appears next frame
4126  window->AutoPosLastDirection = -1;
4127  if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
4128  window->PosFloat = g.IO.MousePos;
4129  }
4130 
4131  // Collapse window by double-clicking on title bar
4132  // 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
4133  if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
4134  {
4135  ImRect title_bar_rect = window->TitleBarRect();
4136  if (g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])
4137  {
4138  window->Collapsed = !window->Collapsed;
4139  MarkIniSettingsDirty(window);
4140  FocusWindow(window);
4141  }
4142  }
4143  else
4144  {
4145  window->Collapsed = false;
4146  }
4147 
4148  // SIZE
4149 
4150  // Save contents size from last frame for auto-fitting (unless explicitly specified)
4151  window->SizeContents.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : ((window_is_new ? 0.0f : window->DC.CursorMaxPos.x - window->Pos.x) + window->Scroll.x));
4152  window->SizeContents.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : ((window_is_new ? 0.0f : window->DC.CursorMaxPos.y - window->Pos.y) + window->Scroll.y));
4153 
4154  // Hide popup/tooltip window when first appearing while we measure size (because we recycle them)
4155  if (window->HiddenFrames > 0)
4156  window->HiddenFrames--;
4157  if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && window_just_activated_by_user)
4158  {
4159  window->HiddenFrames = 1;
4161  {
4162  if (!window_size_set_by_api)
4163  window->Size = window->SizeFull = ImVec2(0.f, 0.f);
4164  window->SizeContents = ImVec2(0.f, 0.f);
4165  }
4166  }
4167 
4168  // Lock window padding so that altering the ShowBorders flag for children doesn't have side-effects.
4170 
4171  // Calculate auto-fit size, handle automatic resize
4172  const ImVec2 size_auto_fit = CalcSizeAutoFit(window);
4173  if (window->Collapsed)
4174  {
4175  // We still process initial auto-fit on collapsed windows to get a window width,
4176  // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
4177  if (window->AutoFitFramesX > 0)
4178  window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
4179  if (window->AutoFitFramesY > 0)
4180  window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
4181  }
4182  else if (!window_size_set_by_api)
4183  {
4185  {
4186  window->SizeFull = size_auto_fit;
4187  }
4188  else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
4189  {
4190  // Auto-fit only grows during the first few frames
4191  if (window->AutoFitFramesX > 0)
4192  window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
4193  if (window->AutoFitFramesY > 0)
4194  window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
4195  MarkIniSettingsDirty(window);
4196  }
4197  }
4198 
4199  // Apply minimum/maximum window size constraints and final size
4200  window->SizeFull = CalcSizeFullWithConstraint(window, window->SizeFull);
4201  window->Size = window->Collapsed ? window->TitleBarRect().GetSize() : window->SizeFull;
4202 
4203  // POSITION
4204 
4205  // Position child window
4206  if (flags & ImGuiWindowFlags_ChildWindow)
4207  {
4208  window->OrderWithinParent = parent_window->DC.ChildWindows.Size;
4209  parent_window->DC.ChildWindows.push_back(window);
4210  }
4211  if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup))
4212  {
4213  window->Pos = window->PosFloat = parent_window->DC.CursorPos;
4214  window->Size = window->SizeFull = size_on_first_use; // NB: argument name 'size_on_first_use' misleading here, it's really just 'size' as provided by user passed via BeginChild()->Begin().
4215  }
4216 
4217  const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFrames == 0);
4218  if (window_pos_with_pivot)
4219  {
4220  // Position given a pivot (e.g. for centering)
4221  SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0);
4222  }
4223  else if (flags & ImGuiWindowFlags_ChildMenu)
4224  {
4225  // Child menus typically request _any_ position within the parent menu item, and then our FindBestPopupWindowPos() function will move the new menu outside the parent bounds.
4226  // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
4227  IM_ASSERT(window_pos_set_by_api);
4228  float horizontal_overlap = style.ItemSpacing.x; // We want some overlap to convey the relative depth of each popup (currently the amount of overlap it is hard-coded to style.ItemSpacing.x, may need to introduce another style value).
4229  ImRect rect_to_avoid;
4230  if (parent_window->DC.MenuBarAppending)
4231  rect_to_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight());
4232  else
4233  rect_to_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);
4234  window->PosFloat = FindBestPopupWindowPos(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
4235  }
4236  else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
4237  {
4238  ImRect rect_to_avoid(window->PosFloat.x - 1, window->PosFloat.y - 1, window->PosFloat.x + 1, window->PosFloat.y + 1);
4239  window->PosFloat = FindBestPopupWindowPos(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
4240  }
4241 
4242  // Position tooltip (always follows mouse)
4243  if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api)
4244  {
4245  ImVec2 ref_pos = g.IO.MousePos;
4246  ImRect rect_to_avoid(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24, ref_pos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead?
4247  window->PosFloat = FindBestPopupWindowPos(ref_pos, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
4248  if (window->AutoPosLastDirection == -1)
4249  window->PosFloat = 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.
4250  }
4251 
4252  // Clamp position so it stays visible
4253  if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
4254  {
4255  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.
4256  {
4257  ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
4258  window->PosFloat = ImMax(window->PosFloat + window->Size, padding) - window->Size;
4259  window->PosFloat = ImMin(window->PosFloat, g.IO.DisplaySize - padding);
4260  }
4261  }
4262  window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y);
4263 
4264  // Default item width. Make it proportional to window size if window manually resizes
4265  if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
4266  window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
4267  else
4268  window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
4269 
4270  // Prepare for focus requests
4271  window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1);
4272  window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1);
4273  window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1;
4274  window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX;
4275 
4276  // Apply scrolling
4277  window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);
4278  window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
4279 
4280  // Modal window darkens what is behind them
4281  if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostModalRootWindow())
4282  window->DrawList->AddRectFilled(fullscreen_rect.Min, fullscreen_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
4283 
4284  // Draw window + handle manual resize
4285  ImRect title_bar_rect = window->TitleBarRect();
4286  const float window_rounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding;
4287  if (window->Collapsed)
4288  {
4289  // Title bar only
4290  RenderFrame(title_bar_rect.Min, title_bar_rect.Max, GetColorU32(ImGuiCol_TitleBgCollapsed), true, window_rounding);
4291  }
4292  else
4293  {
4294  ImU32 resize_col = 0;
4295  const float resize_corner_size = ImMax(g.FontSize * 1.35f, window_rounding + 1.0f + g.FontSize * 0.2f);
4296  if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && !(flags & ImGuiWindowFlags_NoResize))
4297  {
4298  // Manual resize
4299  // Using the FlattenChilds button flag, we make the resize button accessible even if we are hovering over a child window
4300  const ImVec2 br = window->Rect().GetBR();
4301  const ImRect resize_rect(br - ImVec2(resize_corner_size * 0.75f, resize_corner_size * 0.75f), br);
4302  const ImGuiID resize_id = window->GetID("#RESIZE");
4303  bool hovered, held;
4304  ButtonBehavior(resize_rect, resize_id, &hovered, &held, ImGuiButtonFlags_FlattenChilds);
4306  if (hovered || held)
4308 
4309  ImVec2 size_target(FLT_MAX,FLT_MAX);
4310  if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0])
4311  {
4312  // Manual auto-fit when double-clicking
4313  size_target = size_auto_fit;
4314  ClearActiveID();
4315  }
4316  else if (held)
4317  {
4318  // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
4319  size_target = (g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize()) - window->Pos;
4320  }
4321 
4322  if (size_target.x != FLT_MAX && size_target.y != FLT_MAX)
4323  {
4324  window->SizeFull = CalcSizeFullWithConstraint(window, size_target);
4325  MarkIniSettingsDirty(window);
4326  }
4327  window->Size = window->SizeFull;
4328  title_bar_rect = window->TitleBarRect();
4329  }
4330 
4331  // Scrollbars
4332  window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar));
4333  window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > window->Size.x - (window->ScrollbarY ? style.ScrollbarSize : 0.0f) - window->WindowPadding.x) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
4334  if (window->ScrollbarX && !window->ScrollbarY)
4335  window->ScrollbarY = (window->SizeContents.y > window->Size.y + style.ItemSpacing.y - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
4336  window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
4337  window->BorderSize = (flags & ImGuiWindowFlags_ShowBorders) ? 1.0f : 0.0f;
4338 
4339  // Window background, Default Alpha
4340  ImGuiCol bg_color_idx = ImGuiCol_WindowBg;
4341  if ((flags & ImGuiWindowFlags_ComboBox) != 0)
4342  bg_color_idx = ImGuiCol_ComboBg;
4343  else if ((flags & ImGuiWindowFlags_Tooltip) != 0 || (flags & ImGuiWindowFlags_Popup) != 0)
4344  bg_color_idx = ImGuiCol_PopupBg;
4345  else if ((flags & ImGuiWindowFlags_ChildWindow) != 0)
4346  bg_color_idx = ImGuiCol_ChildWindowBg;
4347  ImVec4 bg_color = style.Colors[bg_color_idx]; // We don't use GetColorU32() because bg_alpha is assigned (not multiplied) below
4348  if (bg_alpha >= 0.0f)
4349  bg_color.w = bg_alpha;
4350  bg_color.w *= style.Alpha;
4351  if (bg_color.w > 0.0f)
4352  window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, ColorConvertFloat4ToU32(bg_color), window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImGuiCorner_All : ImGuiCorner_BotLeft|ImGuiCorner_BotRight);
4353 
4354  // Title bar
4355  const bool is_focused = g.NavWindow && window->RootNonPopupWindow == g.NavWindow->RootNonPopupWindow;
4356  if (!(flags & ImGuiWindowFlags_NoTitleBar))
4357  window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), GetColorU32(is_focused ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, ImGuiCorner_TopLeft|ImGuiCorner_TopRight);
4358 
4359  // Menu bar
4360  if (flags & ImGuiWindowFlags_MenuBar)
4361  {
4362  ImRect menu_bar_rect = window->MenuBarRect();
4363  if (flags & ImGuiWindowFlags_ShowBorders)
4364  window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border));
4365  window->DrawList->AddRectFilled(menu_bar_rect.GetTL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImGuiCorner_TopLeft|ImGuiCorner_TopRight);
4366  }
4367 
4368  // Scrollbars
4369  if (window->ScrollbarX)
4370  Scrollbar(window, true);
4371  if (window->ScrollbarY)
4372  Scrollbar(window, false);
4373 
4374  // Render resize grip
4375  // (after the input handling so we don't have a frame of latency)
4376  if (!(flags & ImGuiWindowFlags_NoResize))
4377  {
4378  const ImVec2 br = window->Rect().GetBR();
4379  window->DrawList->PathLineTo(br + ImVec2(-resize_corner_size, -window->BorderSize));
4380  window->DrawList->PathLineTo(br + ImVec2(-window->BorderSize, -resize_corner_size));
4381  window->DrawList->PathArcToFast(ImVec2(br.x - window_rounding - window->BorderSize, br.y - window_rounding - window->BorderSize), window_rounding, 0, 3);
4382  window->DrawList->PathFillConvex(resize_col);
4383  }
4384 
4385  // Borders
4386  if (flags & ImGuiWindowFlags_ShowBorders)
4387  {
4388  window->DrawList->AddRect(window->Pos+ImVec2(1,1), window->Pos+window->Size+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), window_rounding);
4389  window->DrawList->AddRect(window->Pos, window->Pos+window->Size, GetColorU32(ImGuiCol_Border), window_rounding);
4390  if (!(flags & ImGuiWindowFlags_NoTitleBar))
4391  window->DrawList->AddLine(title_bar_rect.GetBL()+ImVec2(1,0), title_bar_rect.GetBR()-ImVec2(1,0), GetColorU32(ImGuiCol_Border));
4392  }
4393  }
4394 
4395  // Update ContentsRegionMax. All the variable it depends on are set above in this function.
4396  window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x;
4397  window->ContentsRegionRect.Min.y = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight();
4398  window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x));
4399  window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y));
4400 
4401  // Setup drawing context
4402  window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x;
4403  window->DC.GroupOffsetX = 0.0f;
4404  window->DC.ColumnsOffsetX = 0.0f;
4405  window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
4406  window->DC.CursorPos = window->DC.CursorStartPos;
4407  window->DC.CursorPosPrevLine = window->DC.CursorPos;
4408  window->DC.CursorMaxPos = window->DC.CursorStartPos;
4409  window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f;
4410  window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
4411  window->DC.MenuBarAppending = false;
4412  window->DC.MenuBarOffsetX = ImMax(window->WindowPadding.x, style.ItemSpacing.x);
4413  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
4414  window->DC.ChildWindows.resize(0);
4417  window->DC.ItemWidth = window->ItemWidthDefault;
4418  window->DC.TextWrapPos = -1.0f; // disabled
4419  window->DC.ItemFlagsStack.resize(0);
4420  window->DC.ItemWidthStack.resize(0);
4421  window->DC.TextWrapPosStack.resize(0);
4422  window->DC.ColumnsCurrent = 0;
4423  window->DC.ColumnsCount = 1;
4424  window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
4425  window->DC.ColumnsStartMaxPosX = window->DC.CursorMaxPos.x;
4426  window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.ColumnsStartPosY;
4427  window->DC.TreeDepth = 0;
4428  window->DC.StateStorage = &window->StateStorage;
4429  window->DC.GroupStack.resize(0);
4430  window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
4431 
4432  if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags))
4433  {
4434  window->DC.ItemFlags = parent_window->DC.ItemFlags;
4435  window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
4436  }
4437 
4438  if (window->AutoFitFramesX > 0)
4439  window->AutoFitFramesX--;
4440  if (window->AutoFitFramesY > 0)
4441  window->AutoFitFramesY--;
4442 
4443  // New windows appears in front (we need to do that AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
4444  if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
4445  if (!(flags & (ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
4446  FocusWindow(window);
4447 
4448  // Title bar
4449  if (!(flags & ImGuiWindowFlags_NoTitleBar))
4450  {
4451  // Collapse button
4452  if (!(flags & ImGuiWindowFlags_NoCollapse))
4453  {
4454  RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f);
4455  }
4456 
4457  // Close button
4458  if (p_open != NULL)
4459  {
4460  const float PAD = 2.0f;
4461  const float rad = (window->TitleBarHeight() - PAD*2.0f) * 0.5f;
4462  if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-PAD - rad, PAD + rad), rad))
4463  *p_open = false;
4464  }
4465 
4466  // Title text (FIXME: refactor text alignment facilities along with RenderText helpers)
4467  const ImVec2 text_size = CalcTextSize(name, NULL, true);
4468  ImVec2 text_min = window->Pos;
4469  ImVec2 text_max = window->Pos + ImVec2(window->Size.x, style.FramePadding.y*2 + text_size.y);
4470  ImRect clip_rect;
4471  clip_rect.Max = ImVec2(window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x), text_max.y); // Match the size of CloseWindowButton()
4472  float pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0 ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : style.FramePadding.x;
4473  float pad_right = (p_open != NULL) ? (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x) : style.FramePadding.x;
4474  if (style.WindowTitleAlign.x > 0.0f) pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x);
4475  text_min.x += pad_left;
4476  text_max.x -= pad_right;
4477  clip_rect.Min = ImVec2(text_min.x, window->Pos.y);
4478  RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect);
4479  }
4480 
4481  // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
4482  window->WindowRectClipped = window->Rect();
4483  window->WindowRectClipped.ClipWith(window->ClipRect);
4484 
4485  // Pressing CTRL+C while holding on a window copy its content to the clipboard
4486  // 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.
4487  // Maybe we can support CTRL+C on every element?
4488  /*
4489  if (g.ActiveId == move_id)
4490  if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
4491  ImGui::LogToClipboard();
4492  */
4493  }
4494 
4495  // Inner clipping rectangle
4496  // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
4497  // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior.
4498  const ImRect title_bar_rect = window->TitleBarRect();
4499  const float border_size = window->BorderSize;
4500  // Force round to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
4501  ImRect clip_rect;
4502  clip_rect.Min.x = ImFloor(0.5f + title_bar_rect.Min.x + ImMax(border_size, ImFloor(window->WindowPadding.x*0.5f)));
4503  clip_rect.Min.y = ImFloor(0.5f + title_bar_rect.Max.y + window->MenuBarHeight() + border_size);
4504  clip_rect.Max.x = ImFloor(0.5f + window->Pos.x + window->Size.x - window->ScrollbarSizes.x - ImMax(border_size, ImFloor(window->WindowPadding.x*0.5f)));
4505  clip_rect.Max.y = ImFloor(0.5f + window->Pos.y + window->Size.y - window->ScrollbarSizes.y - border_size);
4506  PushClipRect(clip_rect.Min, clip_rect.Max, true);
4507 
4508  // Clear 'accessed' flag last thing
4509  if (first_begin_of_the_frame)
4510  window->Accessed = false;
4511  window->BeginCount++;
4512  g.SetNextWindowSizeConstraint = false;
4513 
4514  // Child window can be out of sight and have "negative" clip windows.
4515  // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar).
4516  if (flags & ImGuiWindowFlags_ChildWindow)
4517  {
4518  IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
4519  window->Collapsed = parent_window && parent_window->Collapsed;
4520 
4521  if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
4522  window->Collapsed |= (window->WindowRectClipped.Min.x >= window->WindowRectClipped.Max.x || window->WindowRectClipped.Min.y >= window->WindowRectClipped.Max.y);
4523 
4524  // We also hide the window from rendering because we've already added its border to the command list.
4525  // (we could perform the check earlier in the function but it is simpler at this point)
4526  if (window->Collapsed)
4527  window->Active = false;
4528  }
4529  if (style.Alpha <= 0.0f)
4530  window->Active = false;
4531 
4532  // Return false if we don't intend to display anything to allow user to perform an early out optimization
4533  window->SkipItems = (window->Collapsed || !window->Active) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0;
4534  return !window->SkipItems;
4535 }
4536 
4538 {
4539  ImGuiContext& g = *GImGui;
4540  ImGuiWindow* window = g.CurrentWindow;
4541 
4542  if (window->DC.ColumnsCount != 1) // close columns set if any is open
4543  EndColumns();
4544  PopClipRect(); // inner window clip rectangle
4545 
4546  // Stop logging
4547  if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
4548  LogFinish();
4549 
4550  // Pop
4551  // NB: we don't clear 'window->RootWindow'. The pointer is allowed to live until the next call to Begin().
4553  if (window->Flags & ImGuiWindowFlags_Popup)
4555  CheckStacksSize(window, false);
4556  SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
4557 }
4558 
4559 // Vertical scrollbar
4560 // The entire piece of code below is rather confusing because:
4561 // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
4562 // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
4563 // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
4564 static void Scrollbar(ImGuiWindow* window, bool horizontal)
4565 {
4566  ImGuiContext& g = *GImGui;
4567  const ImGuiStyle& style = g.Style;
4568  const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY");
4569 
4570  // Render background
4571  bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
4572  float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f;
4573  const ImRect window_rect = window->Rect();
4574  const float border_size = window->BorderSize;
4575  ImRect bb = horizontal
4576  ? 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)
4577  : 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);
4578  if (!horizontal)
4579  bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f);
4580  if (bb.GetWidth() <= 0.0f || bb.GetHeight() <= 0.0f)
4581  return;
4582 
4583  float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding;
4584  int window_rounding_corners;
4585  if (horizontal)
4586  window_rounding_corners = ImGuiCorner_BotLeft | (other_scrollbar ? 0 : ImGuiCorner_BotRight);
4587  else
4588  window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImGuiCorner_TopRight : 0) | (other_scrollbar ? 0 : ImGuiCorner_BotRight);
4589  window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_ScrollbarBg), window_rounding, window_rounding_corners);
4590  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)));
4591 
4592  // V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar)
4593  float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
4594  float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y;
4595  float win_size_avail_v = (horizontal ? window->SizeFull.x : window->SizeFull.y) - other_scrollbar_size_w;
4596  float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y;
4597 
4598  // Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount)
4599  // But we maintain a minimum size in pixel to allow for the user to still aim inside.
4600  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.
4601  const float win_size_v = ImMax(ImMax(win_size_contents_v, win_size_avail_v), 1.0f);
4602  const float grab_h_pixels = ImClamp(scrollbar_size_v * (win_size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v);
4603  const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
4604 
4605  // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
4606  bool held = false;
4607  bool hovered = false;
4608  const bool previously_held = (g.ActiveId == id);
4609  ImGui::ButtonBehavior(bb, id, &hovered, &held);
4610 
4611  float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v);
4612  float scroll_ratio = ImSaturate(scroll_v / scroll_max);
4613  float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
4614  if (held && grab_h_norm < 1.0f)
4615  {
4616  float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y;
4617  float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
4618  float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y;
4619 
4620  // Click position in scrollbar normalized space (0.0f->1.0f)
4621  const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);
4622  ImGui::SetHoveredID(id);
4623 
4624  bool seek_absolute = false;
4625  if (!previously_held)
4626  {
4627  // On initial click calculate the distance between mouse and the center of the grab
4628  if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm)
4629  {
4630  *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
4631  }
4632  else
4633  {
4634  seek_absolute = true;
4635  *click_delta_to_grab_center_v = 0.0f;
4636  }
4637  }
4638 
4639  // Apply scroll
4640  // 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
4641  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));
4642  scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
4643  if (horizontal)
4644  window->Scroll.x = scroll_v;
4645  else
4646  window->Scroll.y = scroll_v;
4647 
4648  // Update values for rendering
4649  scroll_ratio = ImSaturate(scroll_v / scroll_max);
4650  grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
4651 
4652  // Update distance to grab now that we have seeked and saturated
4653  if (seek_absolute)
4654  *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
4655  }
4656 
4657  // Render
4659  if (horizontal)
4660  window->DrawList->AddRectFilled(ImVec2(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y), ImVec2(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y), grab_col, style.ScrollbarRounding);
4661  else
4662  window->DrawList->AddRectFilled(ImVec2(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm)), ImVec2(bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels), grab_col, style.ScrollbarRounding);
4663 }
4664 
4665 // Moving window to front of display (which happens to be back of our sorted list)
4667 {
4668  ImGuiContext& g = *GImGui;
4669 
4670  // Always mark the window we passed as focused. This is used for keyboard interactions such as tabbing.
4671  g.NavWindow = window;
4672 
4673  // Passing NULL allow to disable keyboard focus
4674  if (!window)
4675  return;
4676 
4677  // And move its root window to the top of the pile
4678  if (window->RootWindow)
4679  window = window->RootWindow;
4680 
4681  // Steal focus on active widgets
4682  if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it..
4683  if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window)
4684  ClearActiveID();
4685 
4686  // Bring to front
4687  if ((window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) || g.Windows.back() == window)
4688  return;
4689  for (int i = 0; i < g.Windows.Size; i++)
4690  if (g.Windows[i] == window)
4691  {
4692  g.Windows.erase(g.Windows.begin() + i);
4693  break;
4694  }
4695  g.Windows.push_back(window);
4696 }
4697 
4698 void ImGui::PushItemWidth(float item_width)
4699 {
4700  ImGuiWindow* window = GetCurrentWindow();
4701  window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
4702  window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
4703 }
4704 
4705 void ImGui::PushMultiItemsWidths(int components, float w_full)
4706 {
4707  ImGuiWindow* window = GetCurrentWindow();
4708  const ImGuiStyle& style = GImGui->Style;
4709  if (w_full <= 0.0f)
4710  w_full = CalcItemWidth();
4711  const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
4712  const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
4713  window->DC.ItemWidthStack.push_back(w_item_last);
4714  for (int i = 0; i < components-1; i++)
4715  window->DC.ItemWidthStack.push_back(w_item_one);
4716  window->DC.ItemWidth = window->DC.ItemWidthStack.back();
4717 }
4718 
4720 {
4721  ImGuiWindow* window = GetCurrentWindow();
4722  window->DC.ItemWidthStack.pop_back();
4723  window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
4724 }
4725 
4727 {
4728  ImGuiWindow* window = GetCurrentWindowRead();
4729  float w = window->DC.ItemWidth;
4730  if (w < 0.0f)
4731  {
4732  // 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.
4733  float width_to_right_edge = GetContentRegionAvail().x;
4734  w = ImMax(1.0f, width_to_right_edge + w);
4735  }
4736  w = (float)(int)w;
4737  return w;
4738 }
4739 
4740 static ImFont* GetDefaultFont()
4741 {
4742  ImGuiContext& g = *GImGui;
4743  return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0];
4744 }
4745 
4746 static void SetCurrentFont(ImFont* font)
4747 {
4748  ImGuiContext& g = *GImGui;
4749  IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
4750  IM_ASSERT(font->Scale > 0.0f);
4751  g.Font = font;
4753  g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
4755 }
4756 
4758 {
4759  ImGuiContext& g = *GImGui;
4760  if (!font)
4761  font = GetDefaultFont();
4762  SetCurrentFont(font);
4763  g.FontStack.push_back(font);
4765 }
4766 
4768 {
4769  ImGuiContext& g = *GImGui;
4771  g.FontStack.pop_back();
4772  SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
4773 }
4774 
4775 void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
4776 {
4777  ImGuiWindow* window = GetCurrentWindow();
4778  if (enabled)
4779  window->DC.ItemFlags |= option;
4780  else
4781  window->DC.ItemFlags &= ~option;
4782  window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
4783 }
4784 
4786 {
4787  ImGuiWindow* window = GetCurrentWindow();
4788  window->DC.ItemFlagsStack.pop_back();
4789  window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back();
4790 }
4791 
4792 void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
4793 {
4794  PushItemFlag(ImGuiItemFlags_AllowKeyboardFocus, allow_keyboard_focus);
4795 }
4796 
4798 {
4799  PopItemFlag();
4800 }
4801 
4802 void ImGui::PushButtonRepeat(bool repeat)
4803 {
4805 }
4806 
4808 {
4809  PopItemFlag();
4810 }
4811 
4812 void ImGui::PushTextWrapPos(float wrap_pos_x)
4813 {
4814  ImGuiWindow* window = GetCurrentWindow();
4815  window->DC.TextWrapPos = wrap_pos_x;
4816  window->DC.TextWrapPosStack.push_back(wrap_pos_x);
4817 }
4818 
4820 {
4821  ImGuiWindow* window = GetCurrentWindow();
4822  window->DC.TextWrapPosStack.pop_back();
4823  window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
4824 }
4825 
4826 // 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
4828 {
4829  ImGuiContext& g = *GImGui;
4830  ImGuiColMod backup;
4831  backup.Col = idx;
4832  backup.BackupValue = g.Style.Colors[idx];
4833  g.ColorModifiers.push_back(backup);
4834  g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
4835 }
4836 
4838 {
4839  ImGuiContext& g = *GImGui;
4840  ImGuiColMod backup;
4841  backup.Col = idx;
4842  backup.BackupValue = g.Style.Colors[idx];
4843  g.ColorModifiers.push_back(backup);
4844  g.Style.Colors[idx] = col;
4845 }
4846 
4847 void ImGui::PopStyleColor(int count)
4848 {
4849  ImGuiContext& g = *GImGui;
4850  while (count > 0)
4851  {
4852  ImGuiColMod& backup = g.ColorModifiers.back();
4853  g.Style.Colors[backup.Col] = backup.BackupValue;
4855  count--;
4856  }
4857 }
4858 
4860 {
4863  void* GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
4864 };
4865 
4866 static const ImGuiStyleVarInfo GStyleVarInfo[ImGuiStyleVar_Count_] =
4867 {
4868  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) }, // ImGuiStyleVar_Alpha
4869  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) }, // ImGuiStyleVar_WindowPadding
4870  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) }, // ImGuiStyleVar_WindowRounding
4871  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) }, // ImGuiStyleVar_WindowMinSize
4872  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildWindowRounding) }, // ImGuiStyleVar_ChildWindowRounding
4873  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) }, // ImGuiStyleVar_FramePadding
4874  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) }, // ImGuiStyleVar_FrameRounding
4875  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) }, // ImGuiStyleVar_ItemSpacing
4876  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) }, // ImGuiStyleVar_ItemInnerSpacing
4877  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) }, // ImGuiStyleVar_IndentSpacing
4878  { ImGuiDataType_Float, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) }, // ImGuiStyleVar_GrabMinSize
4879  { ImGuiDataType_Float2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
4880 };
4881 
4882 static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
4883 {
4884  IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_Count_);
4885  return &GStyleVarInfo[idx];
4886 }
4887 
4889 {
4890  const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
4891  if (var_info->Type == ImGuiDataType_Float)
4892  {
4893  ImGuiContext& g = *GImGui;
4894  float* pvar = (float*)var_info->GetVarPtr(&g.Style);
4895  g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
4896  *pvar = val;
4897  return;
4898  }
4899  IM_ASSERT(0); // Called function with wrong-type? Variable is not a float.
4900 }
4901 
4903 {
4904  const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
4905  if (var_info->Type == ImGuiDataType_Float2)
4906  {
4907  ImGuiContext& g = *GImGui;
4908  ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
4909  g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
4910  *pvar = val;
4911  return;
4912  }
4913  IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2.
4914 }
4915 
4916 void ImGui::PopStyleVar(int count)
4917 {
4918  ImGuiContext& g = *GImGui;
4919  while (count > 0)
4920  {
4921  ImGuiStyleMod& backup = g.StyleModifiers.back();
4922  const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
4923  if (info->Type == ImGuiDataType_Float) (*(float*)info->GetVarPtr(&g.Style)) = backup.BackupFloat[0];
4924  else if (info->Type == ImGuiDataType_Float2) (*(ImVec2*)info->GetVarPtr(&g.Style)) = ImVec2(backup.BackupFloat[0], backup.BackupFloat[1]);
4925  else if (info->Type == ImGuiDataType_Int) (*(int*)info->GetVarPtr(&g.Style)) = backup.BackupInt[0];
4927  count--;
4928  }
4929 }
4930 
4932 {
4933  // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
4934  switch (idx)
4935  {
4936  case ImGuiCol_Text: return "Text";
4937  case ImGuiCol_TextDisabled: return "TextDisabled";
4938  case ImGuiCol_WindowBg: return "WindowBg";
4939  case ImGuiCol_ChildWindowBg: return "ChildWindowBg";
4940  case ImGuiCol_PopupBg: return "PopupBg";
4941  case ImGuiCol_Border: return "Border";
4942  case ImGuiCol_BorderShadow: return "BorderShadow";
4943  case ImGuiCol_FrameBg: return "FrameBg";
4944  case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
4945  case ImGuiCol_FrameBgActive: return "FrameBgActive";
4946  case ImGuiCol_TitleBg: return "TitleBg";
4947  case ImGuiCol_TitleBgActive: return "TitleBgActive";
4948  case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
4949  case ImGuiCol_MenuBarBg: return "MenuBarBg";
4950  case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
4951  case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
4952  case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
4953  case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
4954  case ImGuiCol_ComboBg: return "ComboBg";
4955  case ImGuiCol_CheckMark: return "CheckMark";
4956  case ImGuiCol_SliderGrab: return "SliderGrab";
4957  case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
4958  case ImGuiCol_Button: return "Button";
4959  case ImGuiCol_ButtonHovered: return "ButtonHovered";
4960  case ImGuiCol_ButtonActive: return "ButtonActive";
4961  case ImGuiCol_Header: return "Header";
4962  case ImGuiCol_HeaderHovered: return "HeaderHovered";
4963  case ImGuiCol_HeaderActive: return "HeaderActive";
4964  case ImGuiCol_Separator: return "Separator";
4965  case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
4966  case ImGuiCol_SeparatorActive: return "SeparatorActive";
4967  case ImGuiCol_ResizeGrip: return "ResizeGrip";
4968  case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
4969  case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
4970  case ImGuiCol_CloseButton: return "CloseButton";
4971  case ImGuiCol_CloseButtonHovered: return "CloseButtonHovered";
4972  case ImGuiCol_CloseButtonActive: return "CloseButtonActive";
4973  case ImGuiCol_PlotLines: return "PlotLines";
4974  case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
4975  case ImGuiCol_PlotHistogram: return "PlotHistogram";
4976  case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
4977  case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
4978  case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening";
4979  }
4980  IM_ASSERT(0);
4981  return "Unknown";
4982 }
4983 
4985 {
4986  ImGuiContext& g = *GImGui;
4987  return g.HoveredWindow == g.CurrentWindow && IsWindowContentHoverable(g.HoveredRootWindow);
4988 }
4989 
4991 {
4992  ImGuiContext& g = *GImGui;
4993  return g.HoveredWindow == g.CurrentWindow;
4994 }
4995 
4997 {
4998  ImGuiContext& g = *GImGui;
4999  return g.NavWindow == g.CurrentWindow;
5000 }
5001 
5003 {
5004  ImGuiContext& g = *GImGui;
5005  return g.NavWindow == g.CurrentWindow->RootWindow;
5006 }
5007 
5009 {
5010  ImGuiContext& g = *GImGui;
5011  return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
5012 }
5013 
5015 {
5016  ImGuiContext& g = *GImGui;
5017  return g.HoveredRootWindow && (g.HoveredRootWindow == g.CurrentWindow->RootWindow) && IsWindowContentHoverable(g.HoveredRootWindow);
5018 }
5019 
5021 {
5022  ImGuiWindow* window = GImGui->CurrentWindow;
5023  return window->Size.x;
5024 }
5025 
5027 {
5028  ImGuiWindow* window = GImGui->CurrentWindow;
5029  return window->Size.y;
5030 }
5031 
5033 {
5034  ImGuiContext& g = *GImGui;
5035  ImGuiWindow* window = g.CurrentWindow;
5036  return window->Pos;
5037 }
5038 
5039 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
5040 {
5041  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.
5042  window->Scroll.y = new_scroll_y;
5043  window->DC.CursorMaxPos.y -= window->Scroll.y;
5044 }
5045 
5046 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
5047 {
5048  // Test condition (NB: bit 0 is always true) and clear flags for next time
5049  if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
5050  return;
5052  window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
5053 
5054  // Set
5055  const ImVec2 old_pos = window->Pos;
5056  window->PosFloat = pos;
5057  window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y);
5058  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
5059  window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected.
5060 }
5061 
5062 void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
5063 {
5064  ImGuiWindow* window = GetCurrentWindowRead();
5065  SetWindowPos(window, pos, cond);
5066 }
5067 
5068 void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
5069 {
5070  if (ImGuiWindow* window = FindWindowByName(name))
5071  SetWindowPos(window, pos, cond);
5072 }
5073 
5075 {
5076  ImGuiWindow* window = GetCurrentWindowRead();
5077  return window->Size;
5078 }
5079 
5080 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
5081 {
5082  // Test condition (NB: bit 0 is always true) and clear flags for next time
5083  if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
5084  return;
5086 
5087  // Set
5088  if (size.x > 0.0f)
5089  {
5090  window->AutoFitFramesX = 0;
5091  window->SizeFull.x = size.x;
5092  }
5093  else
5094  {
5095  window->AutoFitFramesX = 2;
5096  window->AutoFitOnlyGrows = false;
5097  }
5098  if (size.y > 0.0f)
5099  {
5100  window->AutoFitFramesY = 0;
5101  window->SizeFull.y = size.y;
5102  }
5103  else
5104  {
5105  window->AutoFitFramesY = 2;
5106  window->AutoFitOnlyGrows = false;
5107  }
5108 }
5109 
5110 void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
5111 {
5112  SetWindowSize(GImGui->CurrentWindow, size, cond);
5113 }
5114 
5115 void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
5116 {
5117  ImGuiWindow* window = FindWindowByName(name);
5118  if (window)
5119  SetWindowSize(window, size, cond);
5120 }
5121 
5122 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
5123 {
5124  // Test condition (NB: bit 0 is always true) and clear flags for next time
5125  if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
5126  return;
5128 
5129  // Set
5130  window->Collapsed = collapsed;
5131 }
5132 
5133 void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
5134 {
5135  SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
5136 }
5137 
5139 {
5140  ImGuiWindow* window = GetCurrentWindowRead();
5141  return window->Collapsed;
5142 }
5143 
5145 {
5146  ImGuiWindow* window = GetCurrentWindowRead();
5147  return window->Appearing;
5148 }
5149 
5150 void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
5151 {
5152  ImGuiWindow* window = FindWindowByName(name);
5153  if (window)
5154  SetWindowCollapsed(window, collapsed, cond);
5155 }
5156 
5158 {
5159  FocusWindow(GImGui->CurrentWindow);
5160 }
5161 
5162 void ImGui::SetWindowFocus(const char* name)
5163 {
5164  if (name)
5165  {
5166  if (ImGuiWindow* window = FindWindowByName(name))
5167  FocusWindow(window);
5168  }
5169  else
5170  {
5171  FocusWindow(NULL);
5172  }
5173 }
5174 
5175 void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
5176 {
5177  ImGuiContext& g = *GImGui;
5178  g.SetNextWindowPosVal = pos;
5179  g.SetNextWindowPosPivot = pivot;
5180  g.SetNextWindowPosCond = cond ? cond : ImGuiCond_Always;
5181 }
5182 
5183 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
5185 {
5186  SetNextWindowPos(GetIO().DisplaySize * 0.5f, cond, ImVec2(0.5f, 0.5f));
5187 }
5188 #endif
5189 
5191 {
5192  ImGuiContext& g = *GImGui;
5193  g.SetNextWindowSizeVal = size;
5194  g.SetNextWindowSizeCond = cond ? cond : ImGuiCond_Always;
5195 }
5196 
5197 void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback, void* custom_callback_user_data)
5198 {
5199  ImGuiContext& g = *GImGui;
5200  g.SetNextWindowSizeConstraint = true;
5201  g.SetNextWindowSizeConstraintRect = ImRect(size_min, size_max);
5202  g.SetNextWindowSizeConstraintCallback = custom_callback;
5203  g.SetNextWindowSizeConstraintCallbackUserData = custom_callback_user_data;
5204 }
5205 
5207 {
5208  ImGuiContext& g = *GImGui;
5209  g.SetNextWindowContentSizeVal = size;
5211 }
5212 
5214 {
5215  ImGuiContext& g = *GImGui;
5218 }
5219 
5220 void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
5221 {
5222  ImGuiContext& g = *GImGui;
5223  g.SetNextWindowCollapsedVal = collapsed;
5224  g.SetNextWindowCollapsedCond = cond ? cond : ImGuiCond_Always;
5225 }
5226 
5228 {
5229  ImGuiContext& g = *GImGui;
5230  g.SetNextWindowFocus = true;
5231 }
5232 
5233 // In window space (not screen space!)
5235 {
5236  ImGuiWindow* window = GetCurrentWindowRead();
5237  ImVec2 mx = window->ContentsRegionRect.Max;
5238  if (window->DC.ColumnsCount != 1)
5239  mx.x = GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x;
5240  return mx;
5241 }
5242 
5244 {
5245  ImGuiWindow* window = GetCurrentWindowRead();
5246  return GetContentRegionMax() - (window->DC.CursorPos - window->Pos);
5247 }
5248 
5250 {
5251  return GetContentRegionAvail().x;
5252 }
5253 
5254 // In window space (not screen space!)
5256 {
5257  ImGuiWindow* window = GetCurrentWindowRead();
5258  return window->ContentsRegionRect.Min;
5259 }
5260 
5262 {
5263  ImGuiWindow* window = GetCurrentWindowRead();
5264  return window->ContentsRegionRect.Max;
5265 }
5266 
5268 {
5269  ImGuiWindow* window = GetCurrentWindowRead();
5270  return window->ContentsRegionRect.Max.x - window->ContentsRegionRect.Min.x;
5271 }
5272 
5274 {
5275  ImGuiContext& g = *GImGui;
5276  return g.FontSize;
5277 }
5278 
5280 {
5281  ImGuiContext& g = *GImGui;
5282  return g.FontSize + g.Style.ItemSpacing.y;
5283 }
5284 
5286 {
5287  ImGuiContext& g = *GImGui;
5288  return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
5289 }
5290 
5292 {
5293  ImGuiWindow* window = GetCurrentWindow();
5294  return window->DrawList;
5295 }
5296 
5298 {
5299  return GImGui->Font;
5300 }
5301 
5303 {
5304  return GImGui->FontSize;
5305 }
5306 
5308 {
5309  return GImGui->FontTexUvWhitePixel;
5310 }
5311 
5312 void ImGui::SetWindowFontScale(float scale)
5313 {
5314  ImGuiContext& g = *GImGui;
5315  ImGuiWindow* window = GetCurrentWindow();
5316  window->FontWindowScale = scale;
5317  g.FontSize = window->CalcFontSize();
5318 }
5319 
5320 // User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
5321 // Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
5323 {
5324  ImGuiWindow* window = GetCurrentWindowRead();
5325  return window->DC.CursorPos - window->Pos + window->Scroll;
5326 }
5327 
5329 {
5330  ImGuiWindow* window = GetCurrentWindowRead();
5331  return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
5332 }
5333 
5335 {
5336  ImGuiWindow* window = GetCurrentWindowRead();
5337  return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
5338 }
5339 
5340 void ImGui::SetCursorPos(const ImVec2& local_pos)
5341 {
5342  ImGuiWindow* window = GetCurrentWindow();
5343  window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
5344  window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
5345 }
5346 
5348 {
5349  ImGuiWindow* window = GetCurrentWindow();
5350  window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
5351  window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
5352 }
5353 
5355 {
5356  ImGuiWindow* window = GetCurrentWindow();
5357  window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
5358  window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
5359 }
5360 
5362 {
5363  ImGuiWindow* window = GetCurrentWindowRead();
5364  return window->DC.CursorStartPos - window->Pos;
5365 }
5366 
5368 {
5369  ImGuiWindow* window = GetCurrentWindowRead();
5370  return window->DC.CursorPos;
5371 }
5372 
5373 void ImGui::SetCursorScreenPos(const ImVec2& screen_pos)
5374 {
5375  ImGuiWindow* window = GetCurrentWindow();
5376  window->DC.CursorPos = screen_pos;
5377  window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
5378 }
5379 
5381 {
5382  return GImGui->CurrentWindow->Scroll.x;
5383 }
5384 
5386 {
5387  return GImGui->CurrentWindow->Scroll.y;
5388 }
5389 
5391 {
5392  ImGuiWindow* window = GetCurrentWindowRead();
5393  return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x));
5394 }
5395 
5397 {
5398  ImGuiWindow* window = GetCurrentWindowRead();
5399  return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y));
5400 }
5401 
5402 void ImGui::SetScrollX(float scroll_x)
5403 {
5404  ImGuiWindow* window = GetCurrentWindow();
5405  window->ScrollTarget.x = scroll_x;
5406  window->ScrollTargetCenterRatio.x = 0.0f;
5407 }
5408 
5409 void ImGui::SetScrollY(float scroll_y)
5410 {
5411  ImGuiWindow* window = GetCurrentWindow();
5412  window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY
5413  window->ScrollTargetCenterRatio.y = 0.0f;
5414 }
5415 
5416 void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio)
5417 {
5418  // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
5419  ImGuiWindow* window = GetCurrentWindow();
5420  IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
5421  window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y);
5422  if (center_y_ratio <= 0.0f && window->ScrollTarget.y <= window->WindowPadding.y) // Minor hack to make "scroll to top" take account of WindowPadding, else it would scroll to (WindowPadding.y - ItemSpacing.y)
5423  window->ScrollTarget.y = 0.0f;
5424  window->ScrollTargetCenterRatio.y = center_y_ratio;
5425 }
5426 
5427 // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
5428 void ImGui::SetScrollHere(float center_y_ratio)
5429 {
5430  ImGuiWindow* window = GetCurrentWindow();
5431  float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space
5432  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.
5433  SetScrollFromPosY(target_y, center_y_ratio);
5434 }
5435 
5437 {
5438  ImGuiWindow* window = GetCurrentWindow();
5439  window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset;
5440  window->FocusIdxTabRequestNext = INT_MAX;
5441 }
5442 
5444 {
5445  ImGuiWindow* window = GetCurrentWindow();
5446  window->DC.StateStorage = tree ? tree : &window->StateStorage;
5447 }
5448 
5450 {
5451  ImGuiWindow* window = GetCurrentWindowRead();
5452  return window->DC.StateStorage;
5453 }
5454 
5455 void ImGui::TextV(const char* fmt, va_list args)
5456 {
5457  ImGuiWindow* window = GetCurrentWindow();
5458  if (window->SkipItems)
5459  return;
5460 
5461  ImGuiContext& g = *GImGui;
5462  const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
5463  TextUnformatted(g.TempBuffer, text_end);
5464 }
5465 
5466 void ImGui::Text(const char* fmt, ...)
5467 {
5468  va_list args;
5469  va_start(args, fmt);
5470  TextV(fmt, args);
5471  va_end(args);
5472 }
5473 
5474 void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)
5475 {
5477  TextV(fmt, args);
5478  PopStyleColor();
5479 }
5480 
5481 void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
5482 {
5483  va_list args;
5484  va_start(args, fmt);
5485  TextColoredV(col, fmt, args);
5486  va_end(args);
5487 }
5488 
5489 void ImGui::TextDisabledV(const char* fmt, va_list args)
5490 {
5492  TextV(fmt, args);
5493  PopStyleColor();
5494 }
5495 
5496 void ImGui::TextDisabled(const char* fmt, ...)
5497 {
5498  va_list args;
5499  va_start(args, fmt);
5500  TextDisabledV(fmt, args);
5501  va_end(args);
5502 }
5503 
5504 void ImGui::TextWrappedV(const char* fmt, va_list args)
5505 {
5506  bool need_wrap = (GImGui->CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position is one ia already set
5507  if (need_wrap) PushTextWrapPos(0.0f);
5508  TextV(fmt, args);
5509  if (need_wrap) PopTextWrapPos();
5510 }
5511 
5512 void ImGui::TextWrapped(const char* fmt, ...)
5513 {
5514  va_list args;
5515  va_start(args, fmt);
5516  TextWrappedV(fmt, args);
5517  va_end(args);
5518 }
5519 
5520 void ImGui::TextUnformatted(const char* text, const char* text_end)
5521 {
5522  ImGuiWindow* window = GetCurrentWindow();
5523  if (window->SkipItems)
5524  return;
5525 
5526  ImGuiContext& g = *GImGui;
5527  IM_ASSERT(text != NULL);
5528  const char* text_begin = text;
5529  if (text_end == NULL)
5530  text_end = text + strlen(text); // FIXME-OPT
5531 
5532  const float wrap_pos_x = window->DC.TextWrapPos;
5533  const bool wrap_enabled = wrap_pos_x >= 0.0f;
5534  if (text_end - text > 2000 && !wrap_enabled)
5535  {
5536  // Long text!
5537  // Perform manual coarse clipping to optimize for long multi-line text
5538  // From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.
5539  // 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.
5540  const char* line = text;
5541  const float line_height = GetTextLineHeight();
5542  const ImVec2 text_pos = window->DC.CursorPos + ImVec2(0.0f, window->DC.CurrentLineTextBaseOffset);
5543  const ImRect clip_rect = window->ClipRect;
5544  ImVec2 text_size(0,0);
5545 
5546  if (text_pos.y <= clip_rect.Max.y)
5547  {
5548  ImVec2 pos = text_pos;
5549 
5550  // Lines to skip (can't skip when logging text)
5551  if (!g.LogEnabled)
5552  {
5553  int lines_skippable = (int)((clip_rect.Min.y - text_pos.y) / line_height);
5554  if (lines_skippable > 0)
5555  {
5556  int lines_skipped = 0;
5557  while (line < text_end && lines_skipped < lines_skippable)
5558  {
5559  const char* line_end = strchr(line, '\n');
5560  if (!line_end)
5561  line_end = text_end;
5562  line = line_end + 1;
5563  lines_skipped++;
5564  }
5565  pos.y += lines_skipped * line_height;
5566  }
5567  }
5568 
5569  // Lines to render
5570  if (line < text_end)
5571  {
5572  ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));
5573  while (line < text_end)
5574  {
5575  const char* line_end = strchr(line, '\n');
5576  if (IsClippedEx(line_rect, NULL, false))
5577  break;
5578 
5579  const ImVec2 line_size = CalcTextSize(line, line_end, false);
5580  text_size.x = ImMax(text_size.x, line_size.x);
5581  RenderText(pos, line, line_end, false);
5582  if (!line_end)
5583  line_end = text_end;
5584  line = line_end + 1;
5585  line_rect.Min.y += line_height;
5586  line_rect.Max.y += line_height;
5587  pos.y += line_height;
5588  }
5589 
5590  // Count remaining lines
5591  int lines_skipped = 0;
5592  while (line < text_end)
5593  {
5594  const char* line_end = strchr(line, '\n');
5595  if (!line_end)
5596  line_end = text_end;
5597  line = line_end + 1;
5598  lines_skipped++;
5599  }
5600  pos.y += lines_skipped * line_height;
5601  }
5602 
5603  text_size.y += (pos - text_pos).y;
5604  }
5605 
5606  ImRect bb(text_pos, text_pos + text_size);
5607  ItemSize(bb);
5608  ItemAdd(bb, NULL);
5609  }
5610  else
5611  {
5612  const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;
5613  const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
5614 
5615  // Account of baseline offset
5616  ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset);
5617  ImRect bb(text_pos, text_pos + text_size);
5618  ItemSize(text_size);
5619  if (!ItemAdd(bb, NULL))
5620  return;
5621 
5622  // Render (we don't hide text after ## in this end-user function)
5623  RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width);
5624  }
5625 }
5626 
5628 {
5629  ImGuiWindow* window = GetCurrentWindow();
5630  if (window->SkipItems)
5631  return;
5632 
5633  // Declare a dummy item size to that upcoming items that are smaller will center-align on the newly expanded line height.
5634  ImGuiContext& g = *GImGui;
5636  SameLine(0, 0);
5637 }
5638 
5639 // Add a label+text combo aligned to other label+value widgets
5640 void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
5641 {
5642  ImGuiWindow* window = GetCurrentWindow();
5643  if (window->SkipItems)
5644  return;
5645 
5646  ImGuiContext& g = *GImGui;
5647  const ImGuiStyle& style = g.Style;
5648  const float w = CalcItemWidth();
5649 
5650  const ImVec2 label_size = CalcTextSize(label, NULL, true);
5651  const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2));
5652  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);
5653  ItemSize(total_bb, style.FramePadding.y);
5654  if (!ItemAdd(total_bb, NULL))
5655  return;
5656 
5657  // Render
5658  const char* value_text_begin = &g.TempBuffer[0];
5659  const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
5660  RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImVec2(0.0f,0.5f));
5661  if (label_size.x > 0.0f)
5662  RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);
5663 }
5664 
5665 void ImGui::LabelText(const char* label, const char* fmt, ...)
5666 {
5667  va_list args;
5668  va_start(args, fmt);
5669  LabelTextV(label, fmt, args);
5670  va_end(args);
5671 }
5672 
5673 bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags)
5674 {
5675  ImGuiContext& g = *GImGui;
5676  ImGuiWindow* window = GetCurrentWindow();
5677 
5678  if (flags & ImGuiButtonFlags_Disabled)
5679  {
5680  if (out_hovered) *out_hovered = false;
5681  if (out_held) *out_held = false;
5682  if (g.ActiveId == id) ClearActiveID();
5683  return false;
5684  }
5685 
5686  // Default behavior requires click+release on same spot
5689 
5690  ImGuiWindow* backup_hovered_window = g.HoveredWindow;
5691  if ((flags & ImGuiButtonFlags_FlattenChilds) && g.HoveredRootWindow == window)
5692  g.HoveredWindow = window;
5693 
5694  bool pressed = false;
5695  bool hovered = ItemHoverable(bb, id);
5696 
5697  if ((flags & ImGuiButtonFlags_FlattenChilds) && g.HoveredRootWindow == window)
5698  g.HoveredWindow = backup_hovered_window;
5699 
5700  if (hovered)
5701  {
5702  if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt))
5703  {
5704  // | CLICKING | HOLDING with ImGuiButtonFlags_Repeat
5705  // PressedOnClickRelease | <on release>* | <on repeat> <on repeat> .. (NOT on release) <-- MOST COMMON! (*) only if both click/release were over bounds
5706  // PressedOnClick | <on click> | <on click> <on repeat> <on repeat> ..
5707  // PressedOnRelease | <on release> | <on repeat> <on repeat> .. (NOT on release)
5708  // PressedOnDoubleClick | <on dclick> | <on dclick> <on repeat> <on repeat> ..
5710  {
5711  SetActiveID(id, window); // Hold on ID
5712  FocusWindow(window);
5713  g.ActiveIdClickOffset = g.IO.MousePos - bb.Min;
5714  }
5716  {
5717  pressed = true;
5718  ClearActiveID();
5719  FocusWindow(window);
5720  }
5721  if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0])
5722  {
5723  if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release>
5724  pressed = true;
5725  ClearActiveID();
5726  }
5727 
5728  // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above).
5729  // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings.
5730  if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true))
5731  pressed = true;
5732  }
5733  }
5734 
5735  bool held = false;
5736  if (g.ActiveId == id)
5737  {
5738  if (g.IO.MouseDown[0])
5739  {
5740  held = true;
5741  }
5742  else
5743  {
5744  if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease))
5745  if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release>
5746  pressed = true;
5747  ClearActiveID();
5748  }
5749  }
5750 
5751  // 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.
5752  if (hovered && (flags & ImGuiButtonFlags_AllowOverlapMode) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0))
5753  hovered = pressed = held = false;
5754 
5755  if (out_hovered) *out_hovered = hovered;
5756  if (out_held) *out_held = held;
5757 
5758  return pressed;
5759 }
5760 
5761 bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags)
5762 {
5763  ImGuiWindow* window = GetCurrentWindow();
5764  if (window->SkipItems)
5765  return false;
5766 
5767  ImGuiContext& g = *GImGui;
5768  const ImGuiStyle& style = g.Style;
5769  const ImGuiID id = window->GetID(label);
5770  const ImVec2 label_size = CalcTextSize(label, NULL, true);
5771 
5772  ImVec2 pos = window->DC.CursorPos;
5773  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)
5774  pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
5775  ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
5776 
5777  const ImRect bb(pos, pos + size);
5778  ItemSize(bb, style.FramePadding.y);
5779  if (!ItemAdd(bb, &id))
5780  return false;
5781 
5783  bool hovered, held;
5784  bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
5785 
5786  // Render
5787  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
5788  RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
5789  RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
5790 
5791  // Automatically close popups
5792  //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
5793  // CloseCurrentPopup();
5794 
5795  return pressed;
5796 }
5797 
5798 bool ImGui::Button(const char* label, const ImVec2& size_arg)
5799 {
5800  return ButtonEx(label, size_arg, 0);
5801 }
5802 
5803 // Small buttons fits within text without additional vertical spacing.
5804 bool ImGui::SmallButton(const char* label)
5805 {
5806  ImGuiContext& g = *GImGui;
5807  float backup_padding_y = g.Style.FramePadding.y;
5808  g.Style.FramePadding.y = 0.0f;
5809  bool pressed = ButtonEx(label, ImVec2(0,0), ImGuiButtonFlags_AlignTextBaseLine);
5810  g.Style.FramePadding.y = backup_padding_y;
5811  return pressed;
5812 }
5813 
5814 // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack.
5815 // 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)
5816 bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg)
5817 {
5818  ImGuiWindow* window = GetCurrentWindow();
5819  if (window->SkipItems)
5820  return false;
5821 
5822  const ImGuiID id = window->GetID(str_id);
5823  ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);
5824  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
5825  ItemSize(bb);
5826  if (!ItemAdd(bb, &id))
5827  return false;
5828 
5829  bool hovered, held;
5830  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
5831 
5832  return pressed;
5833 }
5834 
5835 // Upper-right button to close a window.
5836 bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
5837 {
5838  ImGuiWindow* window = GetCurrentWindow();
5839 
5840  const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius));
5841 
5842  bool hovered, held;
5843  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
5844 
5845  // Render
5846  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_CloseButtonActive : hovered ? ImGuiCol_CloseButtonHovered : ImGuiCol_CloseButton);
5847  const ImVec2 center = bb.GetCenter();
5848  window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), col, 12);
5849 
5850  const float cross_extent = (radius * 0.7071f) - 1.0f;
5851  if (hovered)
5852  {
5853  window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), GetColorU32(ImGuiCol_Text));
5854  window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), GetColorU32(ImGuiCol_Text));
5855  }
5856 
5857  return pressed;
5858 }
5859 
5860 void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
5861 {
5862  ImGuiWindow* window = GetCurrentWindow();
5863  if (window->SkipItems)
5864  return;
5865 
5866  ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
5867  if (border_col.w > 0.0f)
5868  bb.Max += ImVec2(2,2);
5869  ItemSize(bb);
5870  if (!ItemAdd(bb, NULL))
5871  return;
5872 
5873  if (border_col.w > 0.0f)
5874  {
5875  window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f);
5876  window->DrawList->AddImage(user_texture_id, bb.Min+ImVec2(1,1), bb.Max-ImVec2(1,1), uv0, uv1, GetColorU32(tint_col));
5877  }
5878  else
5879  {
5880  window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col));
5881  }
5882 }
5883 
5884 // frame_padding < 0: uses FramePadding from style (default)
5885 // frame_padding = 0: no framing
5886 // frame_padding > 0: set framing size
5887 // The color used are the button colors.
5888 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)
5889 {
5890  ImGuiWindow* window = GetCurrentWindow();
5891  if (window->SkipItems)
5892  return false;
5893 
5894  ImGuiContext& g = *GImGui;
5895  const ImGuiStyle& style = g.Style;
5896 
5897  // Default to using texture ID as ID. User can still push string/integer prefixes.
5898  // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV.
5899  PushID((void *)user_texture_id);
5900  const ImGuiID id = window->GetID("#image");
5901  PopID();
5902 
5903  const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding;
5904  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2);
5905  const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size);
5906  ItemSize(bb);
5907  if (!ItemAdd(bb, &id))
5908  return false;
5909 
5910  bool hovered, held;
5911  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
5912 
5913  // Render
5914  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
5915  RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding));
5916  if (bg_col.w > 0.0f)
5917  window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col));
5918  window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col));
5919 
5920  return pressed;
5921 }
5922 
5923 // Start logging ImGui output to TTY
5924 void ImGui::LogToTTY(int max_depth)
5925 {
5926  ImGuiContext& g = *GImGui;
5927  if (g.LogEnabled)
5928  return;
5929  ImGuiWindow* window = GetCurrentWindowRead();
5930 
5931  g.LogEnabled = true;
5932  g.LogFile = stdout;
5933  g.LogStartDepth = window->DC.TreeDepth;
5934  if (max_depth >= 0)
5935  g.LogAutoExpandMaxDepth = max_depth;
5936 }
5937 
5938 // Start logging ImGui output to given file
5939 void ImGui::LogToFile(int max_depth, const char* filename)
5940 {
5941  ImGuiContext& g = *GImGui;
5942  if (g.LogEnabled)
5943  return;
5944  ImGuiWindow* window = GetCurrentWindowRead();
5945 
5946  if (!filename)
5947  {
5948  filename = g.IO.LogFilename;
5949  if (!filename)
5950  return;
5951  }
5952 
5953  g.LogFile = ImFileOpen(filename, "ab");
5954  if (!g.LogFile)
5955  {
5956  IM_ASSERT(g.LogFile != NULL); // Consider this an error
5957  return;
5958  }
5959  g.LogEnabled = true;
5960  g.LogStartDepth = window->DC.TreeDepth;
5961  if (max_depth >= 0)
5962  g.LogAutoExpandMaxDepth = max_depth;
5963 }
5964 
5965 // Start logging ImGui output to clipboard
5966 void ImGui::LogToClipboard(int max_depth)
5967 {
5968  ImGuiContext& g = *GImGui;
5969  if (g.LogEnabled)
5970  return;
5971  ImGuiWindow* window = GetCurrentWindowRead();
5972 
5973  g.LogEnabled = true;
5974  g.LogFile = NULL;
5975  g.LogStartDepth = window->DC.TreeDepth;
5976  if (max_depth >= 0)
5977  g.LogAutoExpandMaxDepth = max_depth;
5978 }
5979 
5981 {
5982  ImGuiContext& g = *GImGui;
5983  if (!g.LogEnabled)
5984  return;
5985 
5987  g.LogEnabled = false;
5988  if (g.LogFile != NULL)
5989  {
5990  if (g.LogFile == stdout)
5991  fflush(g.LogFile);
5992  else
5993  fclose(g.LogFile);
5994  g.LogFile = NULL;
5995  }
5996  if (g.LogClipboard->size() > 1)
5997  {
5999  g.LogClipboard->clear();
6000  }
6001 }
6002 
6003 // Helper to display logging buttons
6005 {
6006  ImGuiContext& g = *GImGui;
6007 
6008  PushID("LogButtons");
6009  const bool log_to_tty = Button("Log To TTY"); SameLine();
6010  const bool log_to_file = Button("Log To File"); SameLine();
6011  const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
6012  PushItemWidth(80.0f);
6013  PushAllowKeyboardFocus(false);
6014  SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL);
6016  PopItemWidth();
6017  PopID();
6018 
6019  // Start logging at the end of the function so that the buttons don't appear in the log
6020  if (log_to_tty)
6022  if (log_to_file)
6024  if (log_to_clipboard)
6026 }
6027 
6029 {
6030  if (flags & ImGuiTreeNodeFlags_Leaf)
6031  return true;
6032 
6033  // We only write to the tree storage if the user clicks (or explicitely use SetNextTreeNode*** functions)
6034  ImGuiContext& g = *GImGui;
6035  ImGuiWindow* window = g.CurrentWindow;
6036  ImGuiStorage* storage = window->DC.StateStorage;
6037 
6038  bool is_open;
6039  if (g.SetNextTreeNodeOpenCond != 0)
6040  {
6042  {
6043  is_open = g.SetNextTreeNodeOpenVal;
6044  storage->SetInt(id, is_open);
6045  }
6046  else
6047  {
6048  // We treat ImGuiCond_Once and ImGuiCond_FirstUseEver the same because tree node state are not saved persistently.
6049  const int stored_value = storage->GetInt(id, -1);
6050  if (stored_value == -1)
6051  {
6052  is_open = g.SetNextTreeNodeOpenVal;
6053  storage->SetInt(id, is_open);
6054  }
6055  else
6056  {
6057  is_open = stored_value != 0;
6058  }
6059  }
6061  }
6062  else
6063  {
6064  is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;
6065  }
6066 
6067  // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior).
6068  // NB- If we are above max depth we still allow manually opened nodes to be logged.
6070  is_open = true;
6071 
6072  return is_open;
6073 }
6074 
6075 bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
6076 {
6077  ImGuiWindow* window = GetCurrentWindow();
6078  if (window->SkipItems)
6079  return false;
6080 
6081  ImGuiContext& g = *GImGui;
6082  const ImGuiStyle& style = g.Style;
6083  const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
6084  const ImVec2 padding = display_frame ? style.FramePadding : ImVec2(style.FramePadding.x, 0.0f);
6085 
6086  if (!label_end)
6087  label_end = FindRenderedTextEnd(label);
6088  const ImVec2 label_size = CalcTextSize(label, label_end, false);
6089 
6090  // We vertically grow up to current line height up the typical widget height.
6091  const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset - padding.y); // Latch before ItemSize changes it
6092  const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2);
6093  ImRect bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height));
6094  if (display_frame)
6095  {
6096  // Framed header expand a little outside the default padding
6097  bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1;
6098  bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1;
6099  }
6100 
6101  const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing
6102  const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser
6103  ItemSize(ImVec2(text_width, frame_height), text_base_offset_y);
6104 
6105  // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
6106  // (Ideally we'd want to add a flag for the user to specify we want want the hit test to be done up to the right side of the content or not)
6107  const ImRect interact_bb = display_frame ? bb : ImRect(bb.Min.x, bb.Min.y, bb.Min.x + text_width + style.ItemSpacing.x*2, bb.Max.y);
6108  bool is_open = TreeNodeBehaviorIsOpen(id, flags);
6109  if (!ItemAdd(interact_bb, &id))
6110  {
6111  if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
6112  TreePushRawID(id);
6113  return is_open;
6114  }
6115 
6116  // Flags that affects opening behavior:
6117  // - 0(default) ..................... single-click anywhere to open
6118  // - OpenOnDoubleClick .............. double-click anywhere to open
6119  // - OpenOnArrow .................... single-click on arrow to open
6120  // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
6124  bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
6125  if (pressed && !(flags & ImGuiTreeNodeFlags_Leaf))
6126  {
6128  if (flags & ImGuiTreeNodeFlags_OpenOnArrow)
6129  toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y));
6130  if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
6131  toggled |= g.IO.MouseDoubleClicked[0];
6132  if (toggled)
6133  {
6134  is_open = !is_open;
6135  window->DC.StateStorage->SetInt(id, is_open);
6136  }
6137  }
6140 
6141  // Render
6142  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
6143  const ImVec2 text_pos = bb.Min + ImVec2(text_offset_x, padding.y + text_base_offset_y);
6144  if (display_frame)
6145  {
6146  // Framed type
6147  RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
6148  RenderCollapseTriangle(bb.Min + padding + ImVec2(0.0f, text_base_offset_y), is_open, 1.0f);
6149  if (g.LogEnabled)
6150  {
6151  // 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.
6152  const char log_prefix[] = "\n##";
6153  const char log_suffix[] = "##";
6154  LogRenderedText(&text_pos, log_prefix, log_prefix+3);
6155  RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size);
6156  LogRenderedText(&text_pos, log_suffix+1, log_suffix+3);
6157  }
6158  else
6159  {
6160  RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size);
6161  }
6162  }
6163  else
6164  {
6165  // Unframed typed for tree nodes
6166  if (hovered || (flags & ImGuiTreeNodeFlags_Selected))
6167  RenderFrame(bb.Min, bb.Max, col, false);
6168 
6169  if (flags & ImGuiTreeNodeFlags_Bullet)
6170  RenderBullet(bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y));
6171  else if (!(flags & ImGuiTreeNodeFlags_Leaf))
6172  RenderCollapseTriangle(bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open, 0.70f);
6173  if (g.LogEnabled)
6174  LogRenderedText(&text_pos, ">");
6175  RenderText(text_pos, label, label_end, false);
6176  }
6177 
6178  if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
6179  TreePushRawID(id);
6180  return is_open;
6181 }
6182 
6183 // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag).
6184 // 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().
6185 bool ImGui::CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags)
6186 {
6187  ImGuiWindow* window = GetCurrentWindow();
6188  if (window->SkipItems)
6189  return false;
6190 
6192 }
6193 
6194 bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags)
6195 {
6196  ImGuiWindow* window = GetCurrentWindow();
6197  if (window->SkipItems)
6198  return false;
6199 
6200  if (p_open && !*p_open)
6201  return false;
6202 
6203  ImGuiID id = window->GetID(label);
6205  if (p_open)
6206  {
6207  // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
6208  ImGuiContext& g = *GImGui;
6209  float button_sz = g.FontSize * 0.5f;
6210  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))
6211  *p_open = false;
6212  }
6213 
6214  return is_open;
6215 }
6216 
6217 bool ImGui::TreeNodeEx(const char* label, ImGuiTreeNodeFlags flags)
6218 {
6219  ImGuiWindow* window = GetCurrentWindow();
6220  if (window->SkipItems)
6221  return false;
6222 
6223  return TreeNodeBehavior(window->GetID(label), flags, label, NULL);
6224 }
6225 
6226 bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
6227 {
6228  ImGuiWindow* window = GetCurrentWindow();
6229  if (window->SkipItems)
6230  return false;
6231 
6232  ImGuiContext& g = *GImGui;
6233  const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
6234  return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end);
6235 }
6236 
6237 bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
6238 {
6239  ImGuiWindow* window = GetCurrentWindow();
6240  if (window->SkipItems)
6241  return false;
6242 
6243  ImGuiContext& g = *GImGui;
6244  const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
6245  return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end);
6246 }
6247 
6248 bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args)
6249 {
6250  return TreeNodeExV(str_id, 0, fmt, args);
6251 }
6252 
6253 bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args)
6254 {
6255  return TreeNodeExV(ptr_id, 0, fmt, args);
6256 }
6257 
6258 bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
6259 {
6260  va_list args;
6261  va_start(args, fmt);
6262  bool is_open = TreeNodeExV(str_id, flags, fmt, args);
6263  va_end(args);
6264  return is_open;
6265 }
6266 
6267 bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
6268 {
6269  va_list args;
6270  va_start(args, fmt);
6271  bool is_open = TreeNodeExV(ptr_id, flags, fmt, args);
6272  va_end(args);
6273  return is_open;
6274 }
6275 
6276 bool ImGui::TreeNode(const char* str_id, const char* fmt, ...)
6277 {
6278  va_list args;
6279  va_start(args, fmt);
6280  bool is_open = TreeNodeExV(str_id, 0, fmt, args);
6281  va_end(args);
6282  return is_open;
6283 }
6284 
6285 bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...)
6286 {
6287  va_list args;
6288  va_start(args, fmt);
6289  bool is_open = TreeNodeExV(ptr_id, 0, fmt, args);
6290  va_end(args);
6291  return is_open;
6292 }
6293 
6294 bool ImGui::TreeNode(const char* label)
6295 {
6296  ImGuiWindow* window = GetCurrentWindow();
6297  if (window->SkipItems)
6298  return false;
6299  return TreeNodeBehavior(window->GetID(label), 0, label, NULL);
6300 }
6301 
6303 {
6304  ImGuiContext& g = *GImGui;
6306 }
6307 
6308 // Horizontal distance preceding label when using TreeNode() or Bullet()
6310 {
6311  ImGuiContext& g = *GImGui;
6312  return g.FontSize + (g.Style.FramePadding.x * 2.0f);
6313 }
6314 
6315 void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond)
6316 {
6317  ImGuiContext& g = *GImGui;
6318  g.SetNextTreeNodeOpenVal = is_open;
6319  g.SetNextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always;
6320 }
6321 
6322 void ImGui::PushID(const char* str_id)
6323 {
6324  ImGuiWindow* window = GetCurrentWindowRead();
6325  window->IDStack.push_back(window->GetID(str_id));
6326 }
6327 
6328 void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
6329 {
6330  ImGuiWindow* window = GetCurrentWindowRead();
6331  window->IDStack.push_back(window->GetID(str_id_begin, str_id_end));
6332 }
6333 
6334 void ImGui::PushID(const void* ptr_id)
6335 {
6336  ImGuiWindow* window = GetCurrentWindowRead();
6337  window->IDStack.push_back(window->GetID(ptr_id));
6338 }
6339 
6340 void ImGui::PushID(int int_id)
6341 {
6342  const void* ptr_id = (void*)(intptr_t)int_id;
6343  ImGuiWindow* window = GetCurrentWindowRead();
6344  window->IDStack.push_back(window->GetID(ptr_id));
6345 }
6346 
6348 {
6349  ImGuiWindow* window = GetCurrentWindowRead();
6350  window->IDStack.pop_back();
6351 }
6352 
6353 ImGuiID ImGui::GetID(const char* str_id)
6354 {
6355  return GImGui->CurrentWindow->GetID(str_id);
6356 }
6357 
6358 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
6359 {
6360  return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end);
6361 }
6362 
6363 ImGuiID ImGui::GetID(const void* ptr_id)
6364 {
6365  return GImGui->CurrentWindow->GetID(ptr_id);
6366 }
6367 
6369 {
6370  ImGuiWindow* window = GetCurrentWindow();
6371  if (window->SkipItems)
6372  return;
6373 
6374  ImGuiContext& g = *GImGui;
6375  const ImGuiStyle& style = g.Style;
6376  const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
6377  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height));
6378  ItemSize(bb);
6379  if (!ItemAdd(bb, NULL))
6380  {
6381  SameLine(0, style.FramePadding.x*2);
6382  return;
6383  }
6384 
6385  // Render and stay on same line
6386  RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
6387  SameLine(0, style.FramePadding.x*2);
6388 }
6389 
6390 // Text with a little bullet aligned to the typical tree node.
6391 void ImGui::BulletTextV(const char* fmt, va_list args)
6392 {
6393  ImGuiWindow* window = GetCurrentWindow();
6394  if (window->SkipItems)
6395  return;
6396 
6397  ImGuiContext& g = *GImGui;
6398  const ImGuiStyle& style = g.Style;
6399 
6400  const char* text_begin = g.TempBuffer;
6401  const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
6402  const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
6403  const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
6404  const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
6405  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
6406  ItemSize(bb);
6407  if (!ItemAdd(bb, NULL))
6408  return;
6409 
6410  // Render
6411  RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
6412  RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false);
6413 }
6414 
6415 void ImGui::BulletText(const char* fmt, ...)
6416 {
6417  va_list args;
6418  va_start(args, fmt);
6419  BulletTextV(fmt, args);
6420  va_end(args);
6421 }
6422 
6423 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size)
6424 {
6425  if (data_type == ImGuiDataType_Int)
6426  ImFormatString(buf, buf_size, display_format, *(int*)data_ptr);
6427  else if (data_type == ImGuiDataType_Float)
6428  ImFormatString(buf, buf_size, display_format, *(float*)data_ptr);
6429 }
6430 
6431 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size)
6432 {
6433  if (data_type == ImGuiDataType_Int)
6434  {
6435  if (decimal_precision < 0)
6436  ImFormatString(buf, buf_size, "%d", *(int*)data_ptr);
6437  else
6438  ImFormatString(buf, buf_size, "%.*d", decimal_precision, *(int*)data_ptr);
6439  }
6440  else if (data_type == ImGuiDataType_Float)
6441  {
6442  if (decimal_precision < 0)
6443  ImFormatString(buf, buf_size, "%f", *(float*)data_ptr); // Ideally we'd have a minimum decimal precision of 1 to visually denote that it is a float, while hiding non-significant digits?
6444  else
6445  ImFormatString(buf, buf_size, "%.*f", decimal_precision, *(float*)data_ptr);
6446  }
6447 }
6448 
6449 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const void* value2)// Store into value1
6450 {
6451  if (data_type == ImGuiDataType_Int)
6452  {
6453  if (op == '+')
6454  *(int*)value1 = *(int*)value1 + *(const int*)value2;
6455  else if (op == '-')
6456  *(int*)value1 = *(int*)value1 - *(const int*)value2;
6457  }
6458  else if (data_type == ImGuiDataType_Float)
6459  {
6460  if (op == '+')
6461  *(float*)value1 = *(float*)value1 + *(const float*)value2;
6462  else if (op == '-')
6463  *(float*)value1 = *(float*)value1 - *(const float*)value2;
6464  }
6465 }
6466 
6467 // User can input math operators (e.g. +100) to edit a numerical values.
6468 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format)
6469 {
6470  while (ImCharIsSpace(*buf))
6471  buf++;
6472 
6473  // We don't support '-' op because it would conflict with inputing negative value.
6474  // Instead you can use +-100 to subtract from an existing value
6475  char op = buf[0];
6476  if (op == '+' || op == '*' || op == '/')
6477  {
6478  buf++;
6479  while (ImCharIsSpace(*buf))
6480  buf++;
6481  }
6482  else
6483  {
6484  op = 0;
6485  }
6486  if (!buf[0])
6487  return false;
6488 
6489  if (data_type == ImGuiDataType_Int)
6490  {
6491  if (!scalar_format)
6492  scalar_format = "%d";
6493  int* v = (int*)data_ptr;
6494  const int old_v = *v;
6495  int arg0i = *v;
6496  if (op && sscanf(initial_value_buf, scalar_format, &arg0i) < 1)
6497  return false;
6498 
6499  // 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
6500  float arg1f = 0.0f;
6501  if (op == '+') { if (sscanf(buf, "%f", &arg1f) == 1) *v = (int)(arg0i + arg1f); } // Add (use "+-" to subtract)
6502  else if (op == '*') { if (sscanf(buf, "%f", &arg1f) == 1) *v = (int)(arg0i * arg1f); } // Multiply
6503  else if (op == '/') { if (sscanf(buf, "%f", &arg1f) == 1 && arg1f != 0.0f) *v = (int)(arg0i / arg1f); }// Divide
6504  else { if (sscanf(buf, scalar_format, &arg0i) == 1) *v = arg0i; } // Assign constant (read as integer so big values are not lossy)
6505  return (old_v != *v);
6506  }
6507  else if (data_type == ImGuiDataType_Float)
6508  {
6509  // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in
6510  scalar_format = "%f";
6511  float* v = (float*)data_ptr;
6512  const float old_v = *v;
6513  float arg0f = *v;
6514  if (op && sscanf(initial_value_buf, scalar_format, &arg0f) < 1)
6515  return false;
6516 
6517  float arg1f = 0.0f;
6518  if (sscanf(buf, scalar_format, &arg1f) < 1)
6519  return false;
6520  if (op == '+') { *v = arg0f + arg1f; } // Add (use "+-" to subtract)
6521  else if (op == '*') { *v = arg0f * arg1f; } // Multiply
6522  else if (op == '/') { if (arg1f != 0.0f) *v = arg0f / arg1f; } // Divide
6523  else { *v = arg1f; } // Assign constant
6524  return (old_v != *v);
6525  }
6526 
6527  return false;
6528 }
6529 
6530 // Create text input in place of a slider (when CTRL+Clicking on slider)
6531 // FIXME: Logic is messy and confusing.
6532 bool ImGui::InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision)
6533 {
6534  ImGuiContext& g = *GImGui;
6535  ImGuiWindow* window = GetCurrentWindow();
6536 
6537  // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen)
6538  // On the first frame, g.ScalarAsInputTextId == 0, then on subsequent frames it becomes == id
6539  SetActiveID(g.ScalarAsInputTextId, window);
6540  SetHoveredID(0);
6541  FocusableItemUnregister(window);
6542 
6543  char buf[32];
6544  DataTypeFormatString(data_type, data_ptr, decimal_precision, buf, IM_ARRAYSIZE(buf));
6545  bool text_value_changed = InputTextEx(label, buf, IM_ARRAYSIZE(buf), aabb.GetSize(), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll);
6546  if (g.ScalarAsInputTextId == 0) // First frame we started displaying the InputText widget
6547  {
6548  IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID (else we'd need to store them both, which is also possible)
6550  SetHoveredID(id);
6551  }
6552  if (text_value_changed)
6553  return DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, NULL);
6554  return false;
6555 }
6556 
6557 // Parse display precision back from the display format string
6558 int ImGui::ParseFormatPrecision(const char* fmt, int default_precision)
6559 {
6560  int precision = default_precision;
6561  while ((fmt = strchr(fmt, '%')) != NULL)
6562  {
6563  fmt++;
6564  if (fmt[0] == '%') { fmt++; continue; } // Ignore "%%"
6565  while (*fmt >= '0' && *fmt <= '9')
6566  fmt++;
6567  if (*fmt == '.')
6568  {
6569  fmt = ImAtoi(fmt + 1, &precision);
6570  if (precision < 0 || precision > 10)
6571  precision = default_precision;
6572  }
6573  if (*fmt == 'e' || *fmt == 'E') // Maximum precision with scientific notation
6574  precision = -1;
6575  break;
6576  }
6577  return precision;
6578 }
6579 
6580 static float GetMinimumStepAtDecimalPrecision(int decimal_precision)
6581 {
6582  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 };
6583  return (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : powf(10.0f, (float)-decimal_precision);
6584 }
6585 
6586 float ImGui::RoundScalar(float value, int decimal_precision)
6587 {
6588  // Round past decimal precision
6589  // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
6590  // FIXME: Investigate better rounding methods
6591  if (decimal_precision < 0)
6592  return value;
6593  const float min_step = GetMinimumStepAtDecimalPrecision(decimal_precision);
6594  bool negative = value < 0.0f;
6595  value = fabsf(value);
6596  float remainder = fmodf(value, min_step);
6597  if (remainder <= min_step*0.5f)
6598  value -= remainder;
6599  else
6600  value += (min_step - remainder);
6601  return negative ? -value : value;
6602 }
6603 
6604 static inline float SliderBehaviorCalcRatioFromValue(float v, float v_min, float v_max, float power, float linear_zero_pos)
6605 {
6606  if (v_min == v_max)
6607  return 0.0f;
6608 
6609  const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f);
6610  const float v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min);
6611  if (is_non_linear)
6612  {
6613  if (v_clamped < 0.0f)
6614  {
6615  const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f,v_max) - v_min);
6616  return (1.0f - powf(f, 1.0f/power)) * linear_zero_pos;
6617  }
6618  else
6619  {
6620  const float f = (v_clamped - ImMax(0.0f,v_min)) / (v_max - ImMax(0.0f,v_min));
6621  return linear_zero_pos + powf(f, 1.0f/power) * (1.0f - linear_zero_pos);
6622  }
6623  }
6624 
6625  // Linear slider
6626  return (v_clamped - v_min) / (v_max - v_min);
6627 }
6628 
6629 bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags)
6630 {
6631  ImGuiContext& g = *GImGui;
6632  ImGuiWindow* window = GetCurrentWindow();
6633  const ImGuiStyle& style = g.Style;
6634 
6635  // Draw frame
6636  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
6637 
6638  const bool is_non_linear = (power < 1.0f-0.00001f) || (power > 1.0f+0.00001f);
6639  const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0;
6640 
6641  const float grab_padding = 2.0f;
6642  const float slider_sz = is_horizontal ? (frame_bb.GetWidth() - grab_padding * 2.0f) : (frame_bb.GetHeight() - grab_padding * 2.0f);
6643  float grab_sz;
6644  if (decimal_precision != 0)
6645  grab_sz = ImMin(style.GrabMinSize, slider_sz);
6646  else
6647  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
6648  const float slider_usable_sz = slider_sz - grab_sz;
6649  const float slider_usable_pos_min = (is_horizontal ? frame_bb.Min.x : frame_bb.Min.y) + grab_padding + grab_sz*0.5f;
6650  const float slider_usable_pos_max = (is_horizontal ? frame_bb.Max.x : frame_bb.Max.y) - grab_padding - grab_sz*0.5f;
6651 
6652  // For logarithmic sliders that cross over sign boundary we want the exponential increase to be symmetric around 0.0f
6653  float linear_zero_pos = 0.0f; // 0.0->1.0f
6654  if (v_min * v_max < 0.0f)
6655  {
6656  // Different sign
6657  const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f/power);
6658  const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f/power);
6659  linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0+linear_dist_max_to_0);
6660  }
6661  else
6662  {
6663  // Same sign
6664  linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f;
6665  }
6666 
6667  // Process clicking on the slider
6668  bool value_changed = false;
6669  if (g.ActiveId == id)
6670  {
6671  bool set_new_value = false;
6672  float clicked_t = 0.0f;
6673  if (g.IO.MouseDown[0])
6674  {
6675  const float mouse_abs_pos = is_horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
6676  clicked_t = (slider_usable_sz > 0.0f) ? ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f) : 0.0f;
6677  if (!is_horizontal)
6678  clicked_t = 1.0f - clicked_t;
6679  set_new_value = true;
6680  }
6681  else
6682  {
6683  ClearActiveID();
6684  }
6685 
6686  if (set_new_value)
6687  {
6688  float new_value;
6689  if (is_non_linear)
6690  {
6691  // Account for logarithmic scale on both sides of the zero
6692  if (clicked_t < linear_zero_pos)
6693  {
6694  // Negative: rescale to the negative range before powering
6695  float a = 1.0f - (clicked_t / linear_zero_pos);
6696  a = powf(a, power);
6697  new_value = ImLerp(ImMin(v_max,0.0f), v_min, a);
6698  }
6699  else
6700  {
6701  // Positive: rescale to the positive range before powering
6702  float a;
6703  if (fabsf(linear_zero_pos - 1.0f) > 1.e-6f)
6704  a = (clicked_t - linear_zero_pos) / (1.0f - linear_zero_pos);
6705  else
6706  a = clicked_t;
6707  a = powf(a, power);
6708  new_value = ImLerp(ImMax(v_min,0.0f), v_max, a);
6709  }
6710  }
6711  else
6712  {
6713  // Linear slider
6714  new_value = ImLerp(v_min, v_max, clicked_t);
6715  }
6716 
6717  // Round past decimal precision
6718  new_value = RoundScalar(new_value, decimal_precision);
6719  if (*v != new_value)
6720  {
6721  *v = new_value;
6722  value_changed = true;
6723  }
6724  }
6725  }
6726 
6727  // Draw
6728  float grab_t = SliderBehaviorCalcRatioFromValue(*v, v_min, v_max, power, linear_zero_pos);
6729  if (!is_horizontal)
6730  grab_t = 1.0f - grab_t;
6731  const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
6732  ImRect grab_bb;
6733  if (is_horizontal)
6734  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));
6735  else
6736  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));
6738 
6739  return value_changed;
6740 }
6741 
6742 // Use power!=1.0 for logarithmic sliders.
6743 // Adjust display_format to decorate the value with a prefix or a suffix.
6744 // "%.3f" 1.234
6745 // "%5.2f secs" 01.23 secs
6746 // "Gold: %.0f" Gold: 1
6747 bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format, float power)
6748 {
6749  ImGuiWindow* window = GetCurrentWindow();
6750  if (window->SkipItems)
6751  return false;
6752 
6753  ImGuiContext& g = *GImGui;
6754  const ImGuiStyle& style = g.Style;
6755  const ImGuiID id = window->GetID(label);
6756  const float w = CalcItemWidth();
6757 
6758  const ImVec2 label_size = CalcTextSize(label, NULL, true);
6759  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
6760  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));
6761 
6762  // NB- we don't call ItemSize() yet because we may turn into a text edit box below
6763  if (!ItemAdd(total_bb, &id))
6764  {
6765  ItemSize(total_bb, style.FramePadding.y);
6766  return false;
6767  }
6768  const bool hovered = ItemHoverable(frame_bb, id);
6769 
6770  if (!display_format)
6771  display_format = "%.3f";
6772  int decimal_precision = ParseFormatPrecision(display_format, 3);
6773 
6774  // Tabbing or CTRL-clicking on Slider turns it into an input box
6775  bool start_text_input = false;
6776  const bool tab_focus_requested = FocusableItemRegister(window, id);
6777  if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]))
6778  {
6779  SetActiveID(id, window);
6780  FocusWindow(window);
6781  if (tab_focus_requested || g.IO.KeyCtrl)
6782  {
6783  start_text_input = true;
6784  g.ScalarAsInputTextId = 0;
6785  }
6786  }
6787  if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
6788  return InputScalarAsWidgetReplacement(frame_bb, label, ImGuiDataType_Float, v, id, decimal_precision);
6789 
6790  // Actual slider behavior + render grab
6791  ItemSize(total_bb, style.FramePadding.y);
6792  const bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, power, decimal_precision);
6793 
6794  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
6795  char value_buf[64];
6796  const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
6797  RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f));
6798 
6799  if (label_size.x > 0.0f)
6800  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
6801 
6802  return value_changed;
6803 }
6804 
6805 bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format, float power)
6806 {
6807  ImGuiWindow* window = GetCurrentWindow();
6808  if (window->SkipItems)
6809  return false;
6810 
6811  ImGuiContext& g = *GImGui;
6812  const ImGuiStyle& style = g.Style;
6813  const ImGuiID id = window->GetID(label);
6814 
6815  const ImVec2 label_size = CalcTextSize(label, NULL, true);
6816  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
6817  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));
6818 
6819  ItemSize(bb, style.FramePadding.y);
6820  if (!ItemAdd(frame_bb, &id))
6821  return false;
6822  const bool hovered = ItemHoverable(frame_bb, id);
6823 
6824  if (!display_format)
6825  display_format = "%.3f";
6826  int decimal_precision = ParseFormatPrecision(display_format, 3);
6827 
6828  if (hovered && g.IO.MouseClicked[0])
6829  {
6830  SetActiveID(id, window);
6831  FocusWindow(window);
6832  }
6833 
6834  // Actual slider behavior + render grab
6835  bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, power, decimal_precision, ImGuiSliderFlags_Vertical);
6836 
6837  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
6838  // For the vertical slider we allow centered text to overlap the frame padding
6839  char value_buf[64];
6840  char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
6841  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));
6842  if (label_size.x > 0.0f)
6843  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
6844 
6845  return value_changed;
6846 }
6847 
6848 bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max)
6849 {
6850  float v_deg = (*v_rad) * 360.0f / (2*IM_PI);
6851  bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f);
6852  *v_rad = v_deg * (2*IM_PI) / 360.0f;
6853  return value_changed;
6854 }
6855 
6856 bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format)
6857 {
6858  if (!display_format)
6859  display_format = "%.0f";
6860  float v_f = (float)*v;
6861  bool value_changed = SliderFloat(label, &v_f, (float)v_min, (float)v_max, display_format, 1.0f);
6862  *v = (int)v_f;
6863  return value_changed;
6864 }
6865 
6866 bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format)
6867 {
6868  if (!display_format)
6869  display_format = "%.0f";
6870  float v_f = (float)*v;
6871  bool value_changed = VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, display_format, 1.0f);
6872  *v = (int)v_f;
6873  return value_changed;
6874 }
6875 
6876 // Add multiple sliders on 1 line for compact edition of multiple components
6877 bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* display_format, float power)
6878 {
6879  ImGuiWindow* window = GetCurrentWindow();
6880  if (window->SkipItems)
6881  return false;
6882 
6883  ImGuiContext& g = *GImGui;
6884  bool value_changed = false;
6885  BeginGroup();
6886  PushID(label);
6887  PushMultiItemsWidths(components);
6888  for (int i = 0; i < components; i++)
6889  {
6890  PushID(i);
6891  value_changed |= SliderFloat("##v", &v[i], v_min, v_max, display_format, power);
6893  PopID();
6894  PopItemWidth();
6895  }
6896  PopID();
6897 
6898  TextUnformatted(label, FindRenderedTextEnd(label));
6899  EndGroup();
6900 
6901  return value_changed;
6902 }
6903 
6904 bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power)
6905 {
6906  return SliderFloatN(label, v, 2, v_min, v_max, display_format, power);
6907 }
6908 
6909 bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power)
6910 {
6911  return SliderFloatN(label, v, 3, v_min, v_max, display_format, power);
6912 }
6913 
6914 bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format, float power)
6915 {
6916  return SliderFloatN(label, v, 4, v_min, v_max, display_format, power);
6917 }
6918 
6919 bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* display_format)
6920 {
6921  ImGuiWindow* window = GetCurrentWindow();
6922  if (window->SkipItems)
6923  return false;
6924 
6925  ImGuiContext& g = *GImGui;
6926  bool value_changed = false;
6927  BeginGroup();
6928  PushID(label);
6929  PushMultiItemsWidths(components);
6930  for (int i = 0; i < components; i++)
6931  {
6932  PushID(i);
6933  value_changed |= SliderInt("##v", &v[i], v_min, v_max, display_format);
6935  PopID();
6936  PopItemWidth();
6937  }
6938  PopID();
6939 
6940  TextUnformatted(label, FindRenderedTextEnd(label));
6941  EndGroup();
6942 
6943  return value_changed;
6944 }
6945 
6946 bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format)
6947 {
6948  return SliderIntN(label, v, 2, v_min, v_max, display_format);
6949 }
6950 
6951 bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format)
6952 {
6953  return SliderIntN(label, v, 3, v_min, v_max, display_format);
6954 }
6955 
6956 bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format)
6957 {
6958  return SliderIntN(label, v, 4, v_min, v_max, display_format);
6959 }
6960 
6961 bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power)
6962 {
6963  ImGuiContext& g = *GImGui;
6964  const ImGuiStyle& style = g.Style;
6965 
6966  // Draw frame
6968  RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
6969 
6970  bool value_changed = false;
6971 
6972  // Process clicking on the drag
6973  if (g.ActiveId == id)
6974  {
6975  if (g.IO.MouseDown[0])
6976  {
6978  {
6979  // Lock current value on click
6980  g.DragCurrentValue = *v;
6981  g.DragLastMouseDelta = ImVec2(0.f, 0.f);
6982  }
6983 
6984  if (v_speed == 0.0f && (v_max - v_min) != 0.0f && (v_max - v_min) < FLT_MAX)
6985  v_speed = (v_max - v_min) * g.DragSpeedDefaultRatio;
6986 
6987  float v_cur = g.DragCurrentValue;
6988  const ImVec2 mouse_drag_delta = GetMouseDragDelta(0, 1.0f);
6989  float adjust_delta = 0.0f;
6990  //if (g.ActiveIdSource == ImGuiInputSource_Mouse)
6991  {
6992  adjust_delta = mouse_drag_delta.x - g.DragLastMouseDelta.x;
6993  if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
6994  adjust_delta *= g.DragSpeedScaleFast;
6995  if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
6996  adjust_delta *= g.DragSpeedScaleSlow;
6997  }
6998  adjust_delta *= v_speed;
6999  g.DragLastMouseDelta.x = mouse_drag_delta.x;
7000 
7001  if (fabsf(adjust_delta) > 0.0f)
7002  {
7003  if (fabsf(power - 1.0f) > 0.001f)
7004  {
7005  // Logarithmic curve on both side of 0.0
7006  float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur;
7007  float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f;
7008  float v1 = powf(v0_abs, 1.0f / power) + (adjust_delta * v0_sign);
7009  float v1_abs = v1 >= 0.0f ? v1 : -v1;
7010  float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f; // Crossed sign line
7011  v_cur = powf(v1_abs, power) * v0_sign * v1_sign; // Reapply sign
7012  }
7013  else
7014  {
7015  v_cur += adjust_delta;
7016  }
7017 
7018  // Clamp
7019  if (v_min < v_max)
7020  v_cur = ImClamp(v_cur, v_min, v_max);
7021  g.DragCurrentValue = v_cur;
7022  }
7023 
7024  // Round to user desired precision, then apply
7025  v_cur = RoundScalar(v_cur, decimal_precision);
7026  if (*v != v_cur)
7027  {
7028  *v = v_cur;
7029  value_changed = true;
7030  }
7031  }
7032  else
7033  {
7034  ClearActiveID();
7035  }
7036  }
7037 
7038  return value_changed;
7039 }
7040 
7041 bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* display_format, float power)
7042 {
7043  ImGuiWindow* window = GetCurrentWindow();
7044  if (window->SkipItems)
7045  return false;
7046 
7047  ImGuiContext& g = *GImGui;
7048  const ImGuiStyle& style = g.Style;
7049  const ImGuiID id = window->GetID(label);
7050  const float w = CalcItemWidth();
7051 
7052  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7053  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
7054  const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
7055  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));
7056 
7057  // NB- we don't call ItemSize() yet because we may turn into a text edit box below
7058  if (!ItemAdd(total_bb, &id))
7059  {
7060  ItemSize(total_bb, style.FramePadding.y);
7061  return false;
7062  }
7063  const bool hovered = ItemHoverable(frame_bb, id);
7064 
7065  if (!display_format)
7066  display_format = "%.3f";
7067  int decimal_precision = ParseFormatPrecision(display_format, 3);
7068 
7069  // Tabbing or CTRL-clicking on Drag turns it into an input box
7070  bool start_text_input = false;
7071  const bool tab_focus_requested = FocusableItemRegister(window, id);
7072  if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] || g.IO.MouseDoubleClicked[0])))
7073  {
7074  SetActiveID(id, window);
7075  FocusWindow(window);
7076  if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0])
7077  {
7078  start_text_input = true;
7079  g.ScalarAsInputTextId = 0;
7080  }
7081  }
7082  if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
7083  return InputScalarAsWidgetReplacement(frame_bb, label, ImGuiDataType_Float, v, id, decimal_precision);
7084 
7085  // Actual drag behavior
7086  ItemSize(total_bb, style.FramePadding.y);
7087  const bool value_changed = DragBehavior(frame_bb, id, v, v_speed, v_min, v_max, decimal_precision, power);
7088 
7089  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
7090  char value_buf[64];
7091  const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
7092  RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f,0.5f));
7093 
7094  if (label_size.x > 0.0f)
7095  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
7096 
7097  return value_changed;
7098 }
7099 
7100 bool ImGui::DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* display_format, float power)
7101 {
7102  ImGuiWindow* window = GetCurrentWindow();
7103  if (window->SkipItems)
7104  return false;
7105 
7106  ImGuiContext& g = *GImGui;
7107  bool value_changed = false;
7108  BeginGroup();
7109  PushID(label);
7110  PushMultiItemsWidths(components);
7111  for (int i = 0; i < components; i++)
7112  {
7113  PushID(i);
7114  value_changed |= DragFloat("##v", &v[i], v_speed, v_min, v_max, display_format, power);
7116  PopID();
7117  PopItemWidth();
7118  }
7119  PopID();
7120 
7121  TextUnformatted(label, FindRenderedTextEnd(label));
7122  EndGroup();
7123 
7124  return value_changed;
7125 }
7126 
7127 bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* display_format, float power)
7128 {
7129  return DragFloatN(label, v, 2, v_speed, v_min, v_max, display_format, power);
7130 }
7131 
7132 bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* display_format, float power)
7133 {
7134  return DragFloatN(label, v, 3, v_speed, v_min, v_max, display_format, power);
7135 }
7136 
7137 bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* display_format, float power)
7138 {
7139  return DragFloatN(label, v, 4, v_speed, v_min, v_max, display_format, power);
7140 }
7141 
7142 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* display_format, const char* display_format_max, float power)
7143 {
7144  ImGuiWindow* window = GetCurrentWindow();
7145  if (window->SkipItems)
7146  return false;
7147 
7148  ImGuiContext& g = *GImGui;
7149  PushID(label);
7150  BeginGroup();
7152 
7153  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), display_format, power);
7154  PopItemWidth();
7156  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, display_format_max ? display_format_max : display_format, power);
7157  PopItemWidth();
7159 
7160  TextUnformatted(label, FindRenderedTextEnd(label));
7161  EndGroup();
7162  PopID();
7163 
7164  return value_changed;
7165 }
7166 
7167 // NB: v_speed is float to allow adjusting the drag speed with more precision
7168 bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* display_format)
7169 {
7170  if (!display_format)
7171  display_format = "%.0f";
7172  float v_f = (float)*v;
7173  bool value_changed = DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, display_format);
7174  *v = (int)v_f;
7175  return value_changed;
7176 }
7177 
7178 bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* display_format)
7179 {
7180  ImGuiWindow* window = GetCurrentWindow();
7181  if (window->SkipItems)
7182  return false;
7183 
7184  ImGuiContext& g = *GImGui;
7185  bool value_changed = false;
7186  BeginGroup();
7187  PushID(label);
7188  PushMultiItemsWidths(components);
7189  for (int i = 0; i < components; i++)
7190  {
7191  PushID(i);
7192  value_changed |= DragInt("##v", &v[i], v_speed, v_min, v_max, display_format);
7194  PopID();
7195  PopItemWidth();
7196  }
7197  PopID();
7198 
7199  TextUnformatted(label, FindRenderedTextEnd(label));
7200  EndGroup();
7201 
7202  return value_changed;
7203 }
7204 
7205 bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* display_format)
7206 {
7207  return DragIntN(label, v, 2, v_speed, v_min, v_max, display_format);
7208 }
7209 
7210 bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* display_format)
7211 {
7212  return DragIntN(label, v, 3, v_speed, v_min, v_max, display_format);
7213 }
7214 
7215 bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* display_format)
7216 {
7217  return DragIntN(label, v, 4, v_speed, v_min, v_max, display_format);
7218 }
7219 
7220 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* display_format, const char* display_format_max)
7221 {
7222  ImGuiWindow* window = GetCurrentWindow();
7223  if (window->SkipItems)
7224  return false;
7225 
7226  ImGuiContext& g = *GImGui;
7227  PushID(label);
7228  BeginGroup();
7230 
7231  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), display_format);
7232  PopItemWidth();
7234  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, display_format_max ? display_format_max : display_format);
7235  PopItemWidth();
7237 
7238  TextUnformatted(label, FindRenderedTextEnd(label));
7239  EndGroup();
7240  PopID();
7241 
7242  return value_changed;
7243 }
7244 
7245 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)
7246 {
7247  ImGuiWindow* window = GetCurrentWindow();
7248  if (window->SkipItems)
7249  return;
7250 
7251  ImGuiContext& g = *GImGui;
7252  const ImGuiStyle& style = g.Style;
7253 
7254  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7255  if (graph_size.x == 0.0f)
7256  graph_size.x = CalcItemWidth();
7257  if (graph_size.y == 0.0f)
7258  graph_size.y = label_size.y + (style.FramePadding.y * 2);
7259 
7260  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y));
7261  const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
7262  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));
7263  ItemSize(total_bb, style.FramePadding.y);
7264  if (!ItemAdd(total_bb, NULL))
7265  return;
7266  const bool hovered = ItemHoverable(inner_bb, 0);
7267 
7268  // Determine scale from values if not specified
7269  if (scale_min == FLT_MAX || scale_max == FLT_MAX)
7270  {
7271  float v_min = FLT_MAX;
7272  float v_max = -FLT_MAX;
7273  for (int i = 0; i < values_count; i++)
7274  {
7275  const float v = values_getter(data, i);
7276  v_min = ImMin(v_min, v);
7277  v_max = ImMax(v_max, v);
7278  }
7279  if (scale_min == FLT_MAX)
7280  scale_min = v_min;
7281  if (scale_max == FLT_MAX)
7282  scale_max = v_max;
7283  }
7284 
7285  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
7286 
7287  if (values_count > 0)
7288  {
7289  int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
7290  int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
7291 
7292  // Tooltip on hover
7293  int v_hovered = -1;
7294  if (hovered)
7295  {
7296  const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
7297  const int v_idx = (int)(t * item_count);
7298  IM_ASSERT(v_idx >= 0 && v_idx < values_count);
7299 
7300  const float v0 = values_getter(data, (v_idx + values_offset) % values_count);
7301  const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count);
7302  if (plot_type == ImGuiPlotType_Lines)
7303  SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1);
7304  else if (plot_type == ImGuiPlotType_Histogram)
7305  SetTooltip("%d: %8.4g", v_idx, v0);
7306  v_hovered = v_idx;
7307  }
7308 
7309  const float t_step = 1.0f / (float)res_w;
7310 
7311  float v0 = values_getter(data, (0 + values_offset) % values_count);
7312  float t0 = 0.0f;
7313  ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) / (scale_max - scale_min)) ); // Point in the normalized space of our target rectangle
7314  float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (-scale_min / (scale_max - scale_min)) : (scale_min < 0.0f ? 0.0f : 1.0f); // Where does the zero line stands
7315 
7316  const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);
7318 
7319  for (int n = 0; n < res_w; n++)
7320  {
7321  const float t1 = t0 + t_step;
7322  const int v1_idx = (int)(t0 * item_count + 0.5f);
7323  IM_ASSERT(v1_idx >= 0 && v1_idx < values_count);
7324  const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count);
7325  const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) / (scale_max - scale_min)) );
7326 
7327  // 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.
7328  ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0);
7329  ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t));
7330  if (plot_type == ImGuiPlotType_Lines)
7331  {
7332  window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
7333  }
7334  else if (plot_type == ImGuiPlotType_Histogram)
7335  {
7336  if (pos1.x >= pos0.x + 2.0f)
7337  pos1.x -= 1.0f;
7338  window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
7339  }
7340 
7341  t0 = t1;
7342  tp0 = tp1;
7343  }
7344  }
7345 
7346  // Text overlay
7347  if (overlay_text)
7348  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));
7349 
7350  if (label_size.x > 0.0f)
7351  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
7352 }
7353 
7355 {
7356  const float* Values;
7357  int Stride;
7358 
7359  ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; }
7360 };
7361 
7362 static float Plot_ArrayGetter(void* data, int idx)
7363 {
7365  const float v = *(float*)(void*)((unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride);
7366  return v;
7367 }
7368 
7369 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)
7370 {
7371  ImGuiPlotArrayGetterData data(values, stride);
7372  PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7373 }
7374 
7375 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)
7376 {
7377  PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7378 }
7379 
7380 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)
7381 {
7382  ImGuiPlotArrayGetterData data(values, stride);
7383  PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7384 }
7385 
7386 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)
7387 {
7388  PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7389 }
7390 
7391 // size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size
7392 void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay)
7393 {
7394  ImGuiWindow* window = GetCurrentWindow();
7395  if (window->SkipItems)
7396  return;
7397 
7398  ImGuiContext& g = *GImGui;
7399  const ImGuiStyle& style = g.Style;
7400 
7401  ImVec2 pos = window->DC.CursorPos;
7402  ImRect bb(pos, pos + CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f));
7403  ItemSize(bb, style.FramePadding.y);
7404  if (!ItemAdd(bb, NULL))
7405  return;
7406 
7407  // Render
7408  fraction = ImSaturate(fraction);
7410  bb.Expand(ImVec2(-window->BorderSize, -window->BorderSize));
7411  const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);
7412  RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding);
7413 
7414  // Default displaying the fraction as percentage string, but user can override it
7415  char overlay_buf[32];
7416  if (!overlay)
7417  {
7418  ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction*100+0.01f);
7419  overlay = overlay_buf;
7420  }
7421 
7422  ImVec2 overlay_size = CalcTextSize(overlay, NULL);
7423  if (overlay_size.x > 0.0f)
7424  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);
7425 }
7426 
7427 bool ImGui::Checkbox(const char* label, bool* v)
7428 {
7429  ImGuiWindow* window = GetCurrentWindow();
7430  if (window->SkipItems)
7431  return false;
7432 
7433  ImGuiContext& g = *GImGui;
7434  const ImGuiStyle& style = g.Style;
7435  const ImGuiID id = window->GetID(label);
7436  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7437 
7438  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
7439  ItemSize(check_bb, style.FramePadding.y);
7440 
7441  ImRect total_bb = check_bb;
7442  if (label_size.x > 0)
7443  SameLine(0, style.ItemInnerSpacing.x);
7444  const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size);
7445  if (label_size.x > 0)
7446  {
7447  ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
7448  total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max));
7449  }
7450 
7451  if (!ItemAdd(total_bb, &id))
7452  return false;
7453 
7454  bool hovered, held;
7455  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
7456  if (pressed)
7457  *v = !(*v);
7458 
7459  RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
7460  if (*v)
7461  {
7462  const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
7463  const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
7464  window->DrawList->AddRectFilled(check_bb.Min+ImVec2(pad,pad), check_bb.Max-ImVec2(pad,pad), GetColorU32(ImGuiCol_CheckMark), style.FrameRounding);
7465  }
7466 
7467  if (g.LogEnabled)
7468  LogRenderedText(&text_bb.Min, *v ? "[x]" : "[ ]");
7469  if (label_size.x > 0.0f)
7470  RenderText(text_bb.Min, label);
7471 
7472  return pressed;
7473 }
7474 
7475 bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value)
7476 {
7477  bool v = ((*flags & flags_value) == flags_value);
7478  bool pressed = Checkbox(label, &v);
7479  if (pressed)
7480  {
7481  if (v)
7482  *flags |= flags_value;
7483  else
7484  *flags &= ~flags_value;
7485  }
7486 
7487  return pressed;
7488 }
7489 
7490 bool ImGui::RadioButton(const char* label, bool active)
7491 {
7492  ImGuiWindow* window = GetCurrentWindow();
7493  if (window->SkipItems)
7494  return false;
7495 
7496  ImGuiContext& g = *GImGui;
7497  const ImGuiStyle& style = g.Style;
7498  const ImGuiID id = window->GetID(label);
7499  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7500 
7501  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));
7502  ItemSize(check_bb, style.FramePadding.y);
7503 
7504  ImRect total_bb = check_bb;
7505  if (label_size.x > 0)
7506  SameLine(0, style.ItemInnerSpacing.x);
7507  const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size);
7508  if (label_size.x > 0)
7509  {
7510  ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
7511  total_bb.Add(text_bb);
7512  }
7513 
7514  if (!ItemAdd(total_bb, &id))
7515  return false;
7516 
7517  ImVec2 center = check_bb.GetCenter();
7518  center.x = (float)(int)center.x + 0.5f;
7519  center.y = (float)(int)center.y + 0.5f;
7520  const float radius = check_bb.GetHeight() * 0.5f;
7521 
7522  bool hovered, held;
7523  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
7524 
7525  window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
7526  if (active)
7527  {
7528  const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
7529  const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
7530  window->DrawList->AddCircleFilled(center, radius-pad, GetColorU32(ImGuiCol_CheckMark), 16);
7531  }
7532 
7533  if (window->Flags & ImGuiWindowFlags_ShowBorders)
7534  {
7535  window->DrawList->AddCircle(center+ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16);
7536  window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16);
7537  }
7538 
7539  if (g.LogEnabled)
7540  LogRenderedText(&text_bb.Min, active ? "(x)" : "( )");
7541  if (label_size.x > 0.0f)
7542  RenderText(text_bb.Min, label);
7543 
7544  return pressed;
7545 }
7546 
7547 bool ImGui::RadioButton(const char* label, int* v, int v_button)
7548 {
7549  const bool pressed = RadioButton(label, *v == v_button);
7550  if (pressed)
7551  {
7552  *v = v_button;
7553  }
7554  return pressed;
7555 }
7556 
7557 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end)
7558 {
7559  int line_count = 0;
7560  const char* s = text_begin;
7561  while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding
7562  if (c == '\n')
7563  line_count++;
7564  s--;
7565  if (s[0] != '\n' && s[0] != '\r')
7566  line_count++;
7567  *out_text_end = s;
7568  return line_count;
7569 }
7570 
7571 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
7572 {
7573  ImFont* font = GImGui->Font;
7574  const float line_height = GImGui->FontSize;
7575  const float scale = line_height / font->FontSize;
7576 
7577  ImVec2 text_size = ImVec2(0,0);
7578  float line_width = 0.0f;
7579 
7580  const ImWchar* s = text_begin;
7581  while (s < text_end)
7582  {
7583  unsigned int c = (unsigned int)(*s++);
7584  if (c == '\n')
7585  {
7586  text_size.x = ImMax(text_size.x, line_width);
7587  text_size.y += line_height;
7588  line_width = 0.0f;
7589  if (stop_on_new_line)
7590  break;
7591  continue;
7592  }
7593  if (c == '\r')
7594  continue;
7595 
7596  const float char_width = font->GetCharAdvance((unsigned short)c) * scale;
7597  line_width += char_width;
7598  }
7599 
7600  if (text_size.x < line_width)
7601  text_size.x = line_width;
7602 
7603  if (out_offset)
7604  *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n
7605 
7606  if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n
7607  text_size.y += line_height;
7608 
7609  if (remaining)
7610  *remaining = s;
7611 
7612  return text_size;
7613 }
7614 
7615 // 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)
7616 namespace ImGuiStb
7617 {
7618 
7619 static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
7620 static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->Text[idx]; }
7621 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); }
7622 static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
7623 static ImWchar STB_TEXTEDIT_NEWLINE = '\n';
7624 static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, STB_TEXTEDIT_STRING* obj, int line_start_idx)
7625 {
7626  const ImWchar* text = obj->Text.Data;
7627  const ImWchar* text_remaining = NULL;
7628  const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
7629  r->x0 = 0.0f;
7630  r->x1 = size.x;
7631  r->baseline_y_delta = size.y;
7632  r->ymin = 0.0f;
7633  r->ymax = size.y;
7634  r->num_chars = (int)(text_remaining - (text + line_start_idx));
7635 }
7636 
7637 static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; }
7638 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; }
7639 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; }
7640 #ifdef __APPLE__ // FIXME: Move setting to IO structure
7641 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; }
7642 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; }
7643 #else
7644 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; }
7645 #endif
7646 #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h
7647 #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
7648 
7649 static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING* obj, int pos, int n)
7650 {
7651  ImWchar* dst = obj->Text.Data + pos;
7652 
7653  // We maintain our buffer length in both UTF-8 and wchar formats
7654  obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);
7655  obj->CurLenW -= n;
7656 
7657  // Offset remaining text
7658  const ImWchar* src = obj->Text.Data + pos + n;
7659  while (ImWchar c = *src++)
7660  *dst++ = c;
7661  *dst = '\0';
7662 }
7663 
7664 static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len)
7665 {
7666  const int text_len = obj->CurLenW;
7667  IM_ASSERT(pos <= text_len);
7668  if (new_text_len + text_len + 1 > obj->Text.Size)
7669  return false;
7670 
7671  const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len);
7672  if (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufSizeA)
7673  return false;
7674 
7675  ImWchar* text = obj->Text.Data;
7676  if (pos != text_len)
7677  memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar));
7678  memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar));
7679 
7680  obj->CurLenW += new_text_len;
7681  obj->CurLenA += new_text_len_utf8;
7682  obj->Text[obj->CurLenW] = '\0';
7683 
7684  return true;
7685 }
7686 
7687 // 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)
7688 #define STB_TEXTEDIT_K_LEFT 0x10000 // keyboard input to move cursor left
7689 #define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right
7690 #define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up
7691 #define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down
7692 #define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line
7693 #define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line
7694 #define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text
7695 #define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text
7696 #define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor
7697 #define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor
7698 #define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo
7699 #define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo
7700 #define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word
7701 #define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word
7702 #define STB_TEXTEDIT_K_SHIFT 0x20000
7703 
7704 #define STB_TEXTEDIT_IMPLEMENTATION
7705 #include "stb_textedit.h"
7706 
7707 }
7708 
7710 {
7711  stb_textedit_key(this, &StbState, key);
7712  CursorFollow = true;
7713  CursorAnimReset();
7714 }
7715 
7716 // Public API to manipulate UTF-8 text
7717 // We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar)
7718 // FIXME: The existence of this rarely exercised code path is a bit of a nuisance.
7719 void ImGuiTextEditCallbackData::DeleteChars(int pos, int bytes_count)
7720 {
7721  IM_ASSERT(pos + bytes_count <= BufTextLen);
7722  char* dst = Buf + pos;
7723  const char* src = Buf + pos + bytes_count;
7724  while (char c = *src++)
7725  *dst++ = c;
7726  *dst = '\0';
7727 
7728  if (CursorPos + bytes_count >= pos)
7729  CursorPos -= bytes_count;
7730  else if (CursorPos >= pos)
7731  CursorPos = pos;
7732  SelectionStart = SelectionEnd = CursorPos;
7733  BufDirty = true;
7734  BufTextLen -= bytes_count;
7735 }
7736 
7737 void ImGuiTextEditCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
7738 {
7739  const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
7740  if (new_text_len + BufTextLen + 1 >= BufSize)
7741  return;
7742 
7743  if (BufTextLen != pos)
7744  memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));
7745  memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char));
7746  Buf[BufTextLen + new_text_len] = '\0';
7747 
7748  if (CursorPos >= pos)
7749  CursorPos += new_text_len;
7750  SelectionStart = SelectionEnd = CursorPos;
7751  BufDirty = true;
7752  BufTextLen += new_text_len;
7753 }
7754 
7755 // Return false to discard a character.
7756 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
7757 {
7758  unsigned int c = *p_char;
7759 
7760  if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF)))
7761  {
7762  bool pass = false;
7763  pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline));
7764  pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput));
7765  if (!pass)
7766  return false;
7767  }
7768 
7769  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.
7770  return false;
7771 
7773  {
7775  if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
7776  return false;
7777 
7779  if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))
7780  return false;
7781 
7783  if (c >= 'a' && c <= 'z')
7784  *p_char = (c += (unsigned int)('A'-'a'));
7785 
7787  if (ImCharIsSpace(c))
7788  return false;
7789  }
7790 
7792  {
7793  ImGuiTextEditCallbackData callback_data;
7794  memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
7796  callback_data.EventChar = (ImWchar)c;
7797  callback_data.Flags = flags;
7798  callback_data.UserData = user_data;
7799  if (callback(&callback_data) != 0)
7800  return false;
7801  *p_char = callback_data.EventChar;
7802  if (!callback_data.EventChar)
7803  return false;
7804  }
7805 
7806  return true;
7807 }
7808 
7809 // Edit a string of text
7810 // 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.
7811 // 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
7812 bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
7813 {
7814  ImGuiWindow* window = GetCurrentWindow();
7815  if (window->SkipItems)
7816  return false;
7817 
7818  IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys)
7819  IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)
7820 
7821  ImGuiContext& g = *GImGui;
7822  const ImGuiIO& io = g.IO;
7823  const ImGuiStyle& style = g.Style;
7824 
7825  const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
7826  const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
7827  const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
7828 
7829  if (is_multiline) // Open group before calling GetID() because groups tracks id created during their spawn
7830  BeginGroup();
7831  const ImGuiID id = window->GetID(label);
7832  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7833  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
7834  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
7835  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));
7836 
7837  ImGuiWindow* draw_window = window;
7838  if (is_multiline)
7839  {
7840  if (!BeginChildFrame(id, frame_bb.GetSize()))
7841  {
7842  EndChildFrame();
7843  EndGroup();
7844  return false;
7845  }
7846  draw_window = GetCurrentWindow();
7847  size.x -= draw_window->ScrollbarSizes.x;
7848  }
7849  else
7850  {
7851  ItemSize(total_bb, style.FramePadding.y);
7852  if (!ItemAdd(total_bb, &id))
7853  return false;
7854  }
7855  const bool hovered = ItemHoverable(frame_bb, id);
7856  if (hovered)
7858 
7859  // Password pushes a temporary font with only a fallback glyph
7860  if (is_password)
7861  {
7862  const ImFontGlyph* glyph = g.Font->FindGlyph('*');
7863  ImFont* password_font = &g.InputTextPasswordFont;
7864  password_font->FontSize = g.Font->FontSize;
7865  password_font->Scale = g.Font->Scale;
7866  password_font->DisplayOffset = g.Font->DisplayOffset;
7867  password_font->Ascent = g.Font->Ascent;
7868  password_font->Descent = g.Font->Descent;
7869  password_font->ContainerAtlas = g.Font->ContainerAtlas;
7870  password_font->FallbackGlyph = glyph;
7871  password_font->FallbackAdvanceX = glyph->AdvanceX;
7872  IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty());
7873  PushFont(password_font);
7874  }
7875 
7876  // NB: we are only allowed to access 'edit_state' if we are the active widget.
7877  ImGuiTextEditState& edit_state = g.InputTextState;
7878 
7879  const bool focus_requested = FocusableItemRegister(window, id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing
7880  const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
7881  const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
7882 
7883  const bool user_clicked = hovered && io.MouseClicked[0];
7884  const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetIDNoKeepAlive("#SCROLLY");
7885 
7886  bool clear_active_id = false;
7887 
7888  bool select_all = (g.ActiveId != id) && (flags & ImGuiInputTextFlags_AutoSelectAll) != 0;
7889  if (focus_requested || user_clicked || user_scrolled)
7890  {
7891  if (g.ActiveId != id)
7892  {
7893  // Start edition
7894  // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
7895  // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
7896  const int prev_len_w = edit_state.CurLenW;
7897  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.
7898  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.
7899  ImStrncpy(edit_state.InitialText.Data, buf, edit_state.InitialText.Size);
7900  const char* buf_end = NULL;
7901  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
7902  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.
7903  edit_state.CursorAnimReset();
7904 
7905  // Preserve cursor position and undo/redo stack if we come back to same widget
7906  // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
7907  const bool recycle_state = (edit_state.Id == id) && (prev_len_w == edit_state.CurLenW);
7908  if (recycle_state)
7909  {
7910  // Recycle existing cursor/selection/undo stack but clamp position
7911  // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
7912  edit_state.CursorClamp();
7913  }
7914  else
7915  {
7916  edit_state.Id = id;
7917  edit_state.ScrollX = 0.0f;
7918  stb_textedit_initialize_state(&edit_state.StbState, !is_multiline);
7919  if (!is_multiline && focus_requested_by_code)
7920  select_all = true;
7921  }
7923  edit_state.StbState.insert_mode = true;
7924  if (!is_multiline && (focus_requested_by_tab || (user_clicked && io.KeyCtrl)))
7925  select_all = true;
7926  }
7927  SetActiveID(id, window);
7928  FocusWindow(window);
7929  }
7930  else if (io.MouseClicked[0])
7931  {
7932  // Release focus when we click outside
7933  clear_active_id = true;
7934  }
7935 
7936  bool value_changed = false;
7937  bool enter_pressed = false;
7938 
7939  if (g.ActiveId == id)
7940  {
7941  if (!is_editable && !g.ActiveIdIsJustActivated)
7942  {
7943  // When read-only we always use the live data passed to the function
7944  edit_state.Text.resize(buf_size+1);
7945  const char* buf_end = NULL;
7946  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
7947  edit_state.CurLenA = (int)(buf_end - buf);
7948  edit_state.CursorClamp();
7949  }
7950 
7951  edit_state.BufSizeA = buf_size;
7952 
7953  // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
7954  // Down the line we should have a cleaner library-wide concept of Selected vs Active.
7955  g.ActiveIdAllowOverlap = !io.MouseDown[0];
7956  g.WantTextInputNextFrame = 1;
7957 
7958  // Edit in progress
7959  const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
7960  const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
7961 
7962  const bool osx_double_click_selects_words = io.OSXBehaviors; // OS X style: Double click selects by word instead of selecting whole text
7963  if (select_all || (hovered && !osx_double_click_selects_words && io.MouseDoubleClicked[0]))
7964  {
7965  edit_state.SelectAll();
7966  edit_state.SelectedAllMouseLock = true;
7967  }
7968  else if (hovered && osx_double_click_selects_words && io.MouseDoubleClicked[0])
7969  {
7970  // Select a word only, OS X style (by simulating keystrokes)
7973  }
7974  else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock)
7975  {
7976  stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
7977  edit_state.CursorAnimReset();
7978  }
7979  else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
7980  {
7981  stb_textedit_drag(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
7982  edit_state.CursorAnimReset();
7983  edit_state.CursorFollow = true;
7984  }
7985  if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
7986  edit_state.SelectedAllMouseLock = false;
7987 
7988  if (io.InputCharacters[0])
7989  {
7990  // Process text input (before we check for Return because using some IME will effectively send a Return?)
7991  // We ignore CTRL inputs, but need to allow CTRL+ALT as some keyboards (e.g. German) use AltGR - which is Alt+Ctrl - to input certain characters.
7992  if (!(io.KeyCtrl && !io.KeyAlt) && is_editable)
7993  {
7994  for (int n = 0; n < IM_ARRAYSIZE(io.InputCharacters) && io.InputCharacters[n]; n++)
7995  if (unsigned int c = (unsigned int)io.InputCharacters[n])
7996  {
7997  // Insert character if they pass filtering
7998  if (!InputTextFilterCharacter(&c, flags, callback, user_data))
7999  continue;
8000  edit_state.OnKeyPressed((int)c);
8001  }
8002  }
8003 
8004  // Consume characters
8005  memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
8006  }
8007  }
8008 
8009  bool cancel_edit = false;
8010  if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
8011  {
8012  // Handle key-presses
8013  const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
8014  const bool is_shortcut_key_only = (io.OSXBehaviors ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
8015  const bool is_wordmove_key_down = io.OSXBehaviors ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
8016  const bool is_startend_key_down = io.OSXBehaviors && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
8017 
8018  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); }
8019  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); }
8020  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); }
8021  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); }
8022  else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
8023  else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
8024  else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
8025  else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable)
8026  {
8027  if (!edit_state.HasSelection())
8028  {
8029  if (is_wordmove_key_down) edit_state.OnKeyPressed(STB_TEXTEDIT_K_WORDLEFT|STB_TEXTEDIT_K_SHIFT);
8030  else if (io.OSXBehaviors && io.KeySuper && !io.KeyAlt && !io.KeyCtrl) edit_state.OnKeyPressed(STB_TEXTEDIT_K_LINESTART|STB_TEXTEDIT_K_SHIFT);
8031  }
8032  edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
8033  }
8034  else if (IsKeyPressedMap(ImGuiKey_Enter))
8035  {
8036  bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
8037  if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
8038  {
8039  enter_pressed = clear_active_id = true;
8040  }
8041  else if (is_editable)
8042  {
8043  unsigned int c = '\n'; // Insert new line
8044  if (InputTextFilterCharacter(&c, flags, callback, user_data))
8045  edit_state.OnKeyPressed((int)c);
8046  }
8047  }
8048  else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !io.KeyCtrl && !io.KeyShift && !io.KeyAlt && is_editable)
8049  {
8050  unsigned int c = '\t'; // Insert TAB
8051  if (InputTextFilterCharacter(&c, flags, callback, user_data))
8052  edit_state.OnKeyPressed((int)c);
8053  }
8054  else if (IsKeyPressedMap(ImGuiKey_Escape)) { clear_active_id = cancel_edit = true; }
8055  else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
8056  else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
8057  else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; }
8058  else if (is_shortcut_key_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection()))
8059  {
8060  // Cut, Copy
8061  const bool cut = IsKeyPressedMap(ImGuiKey_X);
8062  if (cut && !edit_state.HasSelection())
8063  edit_state.SelectAll();
8064 
8065  if (io.SetClipboardTextFn)
8066  {
8067  const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0;
8068  const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW;
8069  edit_state.TempTextBuffer.resize((ie-ib) * 4 + 1);
8070  ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data+ib, edit_state.Text.Data+ie);
8071  SetClipboardText(edit_state.TempTextBuffer.Data);
8072  }
8073 
8074  if (cut)
8075  {
8076  edit_state.CursorFollow = true;
8077  stb_textedit_cut(&edit_state, &edit_state.StbState);
8078  }
8079  }
8080  else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_V) && is_editable)
8081  {
8082  // Paste
8083  if (const char* clipboard = GetClipboardText())
8084  {
8085  // Filter pasted buffer
8086  const int clipboard_len = (int)strlen(clipboard);
8087  ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
8088  int clipboard_filtered_len = 0;
8089  for (const char* s = clipboard; *s; )
8090  {
8091  unsigned int c;
8092  s += ImTextCharFromUtf8(&c, s, NULL);
8093  if (c == 0)
8094  break;
8095  if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
8096  continue;
8097  clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
8098  }
8099  clipboard_filtered[clipboard_filtered_len] = 0;
8100  if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
8101  {
8102  stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
8103  edit_state.CursorFollow = true;
8104  }
8105  ImGui::MemFree(clipboard_filtered);
8106  }
8107  }
8108  }
8109 
8110  if (g.ActiveId == id)
8111  {
8112  if (cancel_edit)
8113  {
8114  // Restore initial value
8115  if (is_editable)
8116  {
8117  ImStrncpy(buf, edit_state.InitialText.Data, buf_size);
8118  value_changed = true;
8119  }
8120  }
8121 
8122  // 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.
8123  // 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.
8124  bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
8125  if (apply_edit_back_to_user_buffer)
8126  {
8127  // Apply new value immediately - copy modified buffer back
8128  // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer
8129  // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect.
8130  // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
8131  if (is_editable)
8132  {
8133  edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4);
8134  ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data, NULL);
8135  }
8136 
8137  // User callback
8138  if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0)
8139  {
8140  IM_ASSERT(callback != NULL);
8141 
8142  // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.
8143  ImGuiInputTextFlags event_flag = 0;
8144  ImGuiKey event_key = ImGuiKey_COUNT;
8145  if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab))
8146  {
8148  event_key = ImGuiKey_Tab;
8149  }
8150  else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow))
8151  {
8153  event_key = ImGuiKey_UpArrow;
8154  }
8155  else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow))
8156  {
8158  event_key = ImGuiKey_DownArrow;
8159  }
8160  else if (flags & ImGuiInputTextFlags_CallbackAlways)
8162 
8163  if (event_flag)
8164  {
8165  ImGuiTextEditCallbackData callback_data;
8166  memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
8167  callback_data.EventFlag = event_flag;
8168  callback_data.Flags = flags;
8169  callback_data.UserData = user_data;
8170  callback_data.ReadOnly = !is_editable;
8171 
8172  callback_data.EventKey = event_key;
8173  callback_data.Buf = edit_state.TempTextBuffer.Data;
8174  callback_data.BufTextLen = edit_state.CurLenA;
8175  callback_data.BufSize = edit_state.BufSizeA;
8176  callback_data.BufDirty = false;
8177 
8178  // 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)
8179  ImWchar* text = edit_state.Text.Data;
8180  const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.cursor);
8181  const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_start);
8182  const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_end);
8183 
8184  // Call user code
8185  callback(&callback_data);
8186 
8187  // Read back what user may have modified
8188  IM_ASSERT(callback_data.Buf == edit_state.TempTextBuffer.Data); // Invalid to modify those fields
8189  IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA);
8190  IM_ASSERT(callback_data.Flags == flags);
8191  if (callback_data.CursorPos != utf8_cursor_pos) edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos);
8192  if (callback_data.SelectionStart != utf8_selection_start) edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart);
8193  if (callback_data.SelectionEnd != utf8_selection_end) edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd);
8194  if (callback_data.BufDirty)
8195  {
8196  IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
8197  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, callback_data.Buf, NULL);
8198  edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
8199  edit_state.CursorAnimReset();
8200  }
8201  }
8202  }
8203 
8204  // Copy back to user buffer
8205  if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0)
8206  {
8207  ImStrncpy(buf, edit_state.TempTextBuffer.Data, buf_size);
8208  value_changed = true;
8209  }
8210  }
8211  }
8212 
8213  // Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
8214  if (clear_active_id && g.ActiveId == id)
8215  ClearActiveID();
8216 
8217  // Render
8218  // 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.
8219  const char* buf_display = (g.ActiveId == id && is_editable) ? edit_state.TempTextBuffer.Data : buf; buf = NULL;
8220 
8221  if (!is_multiline)
8222  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
8223 
8224  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
8225  ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
8226  ImVec2 text_size(0.f, 0.f);
8227  const bool is_currently_scrolling = (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetIDNoKeepAlive("#SCROLLY"));
8228  if (g.ActiveId == id || is_currently_scrolling)
8229  {
8230  edit_state.CursorAnim += io.DeltaTime;
8231 
8232  // This is going to be messy. We need to:
8233  // - Display the text (this alone can be more easily clipped)
8234  // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
8235  // - Measure text height (for scrollbar)
8236  // 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)
8237  // FIXME: This should occur on buf_display but we'd need to maintain cursor/select_start/select_end for UTF-8.
8238  const ImWchar* text_begin = edit_state.Text.Data;
8239  ImVec2 cursor_offset, select_start_offset;
8240 
8241  {
8242  // Count lines + find lines numbers straddling 'cursor' and 'select_start' position.
8243  const ImWchar* searches_input_ptr[2];
8244  searches_input_ptr[0] = text_begin + edit_state.StbState.cursor;
8245  searches_input_ptr[1] = NULL;
8246  int searches_remaining = 1;
8247  int searches_result_line_number[2] = { -1, -999 };
8248  if (edit_state.StbState.select_start != edit_state.StbState.select_end)
8249  {
8250  searches_input_ptr[1] = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
8251  searches_result_line_number[1] = -1;
8252  searches_remaining++;
8253  }
8254 
8255  // Iterate all lines to find our line numbers
8256  // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
8257  searches_remaining += is_multiline ? 1 : 0;
8258  int line_count = 0;
8259  for (const ImWchar* s = text_begin; *s != 0; s++)
8260  if (*s == '\n')
8261  {
8262  line_count++;
8263  if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; }
8264  if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; }
8265  }
8266  line_count++;
8267  if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count;
8268  if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count;
8269 
8270  // Calculate 2d position by finding the beginning of the line and measuring distance
8271  cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
8272  cursor_offset.y = searches_result_line_number[0] * g.FontSize;
8273  if (searches_result_line_number[1] >= 0)
8274  {
8275  select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
8276  select_start_offset.y = searches_result_line_number[1] * g.FontSize;
8277  }
8278 
8279  // Store text height (note that we haven't calculated text width at all, see GitHub issues #383, #1224)
8280  if (is_multiline)
8281  text_size = ImVec2(size.x, line_count * g.FontSize);
8282  }
8283 
8284  // Scroll
8285  if (edit_state.CursorFollow)
8286  {
8287  // Horizontal scroll in chunks of quarter width
8289  {
8290  const float scroll_increment_x = size.x * 0.25f;
8291  if (cursor_offset.x < edit_state.ScrollX)
8292  edit_state.ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
8293  else if (cursor_offset.x - size.x >= edit_state.ScrollX)
8294  edit_state.ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
8295  }
8296  else
8297  {
8298  edit_state.ScrollX = 0.0f;
8299  }
8300 
8301  // Vertical scroll
8302  if (is_multiline)
8303  {
8304  float scroll_y = draw_window->Scroll.y;
8305  if (cursor_offset.y - g.FontSize < scroll_y)
8306  scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
8307  else if (cursor_offset.y - size.y >= scroll_y)
8308  scroll_y = cursor_offset.y - size.y;
8309  draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // To avoid a frame of lag
8310  draw_window->Scroll.y = scroll_y;
8311  render_pos.y = draw_window->DC.CursorPos.y;
8312  }
8313  }
8314  edit_state.CursorFollow = false;
8315  const ImVec2 render_scroll = ImVec2(edit_state.ScrollX, 0.0f);
8316 
8317  // Draw selection
8318  if (edit_state.StbState.select_start != edit_state.StbState.select_end)
8319  {
8320  const ImWchar* text_selected_begin = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
8321  const ImWchar* text_selected_end = text_begin + ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end);
8322 
8323  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.
8324  float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
8326  ImVec2 rect_pos = render_pos + select_start_offset - render_scroll;
8327  for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
8328  {
8329  if (rect_pos.y > clip_rect.w + g.FontSize)
8330  break;
8331  if (rect_pos.y < clip_rect.y)
8332  {
8333  while (p < text_selected_end)
8334  if (*p++ == '\n')
8335  break;
8336  }
8337  else
8338  {
8339  ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true);
8340  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
8341  ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn));
8342  rect.ClipWith(clip_rect);
8343  if (rect.Overlaps(clip_rect))
8344  draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
8345  }
8346  rect_pos.x = render_pos.x - render_scroll.x;
8347  rect_pos.y += g.FontSize;
8348  }
8349  }
8350 
8351  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);
8352 
8353  // Draw blinking cursor
8354  bool cursor_is_visible = (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f;
8355  ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll;
8356  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);
8357  if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
8358  draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
8359 
8360  // 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.)
8361  if (is_editable)
8362  g.OsImePosRequest = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
8363  }
8364  else
8365  {
8366  // Render text only
8367  const char* buf_end = NULL;
8368  if (is_multiline)
8369  text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_end) * g.FontSize); // We don't need width
8370  draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf_display, buf_end, 0.0f, is_multiline ? NULL : &clip_rect);
8371  }
8372 
8373  if (is_multiline)
8374  {
8375  Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line
8376  EndChildFrame();
8377  EndGroup();
8378  }
8379 
8380  if (is_password)
8381  PopFont();
8382 
8383  // Log as text
8384  if (g.LogEnabled && !is_password)
8385  LogRenderedText(&render_pos, buf_display, NULL);
8386 
8387  if (label_size.x > 0)
8388  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
8389 
8390  if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
8391  return enter_pressed;
8392  else
8393  return value_changed;
8394 }
8395 
8396 bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
8397 {
8398  IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()
8399  return InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data);
8400 }
8401 
8402 bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
8403 {
8404  return InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
8405 }
8406 
8407 static inline float SmallSquareSize()
8408 {
8409  ImGuiContext& g = *GImGui;
8410  return g.FontSize + g.Style.FramePadding.y * 2.0f;
8411 }
8412 
8413 // NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "display_format" argument)
8414 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)
8415 {
8416  ImGuiWindow* window = GetCurrentWindow();
8417  if (window->SkipItems)
8418  return false;
8419 
8420  ImGuiContext& g = *GImGui;
8421  const ImGuiStyle& style = g.Style;
8422  const ImVec2 label_size = CalcTextSize(label, NULL, true);
8423 
8424  BeginGroup();
8425  PushID(label);
8426  const ImVec2 button_sz = ImVec2(SmallSquareSize(), SmallSquareSize());
8427  if (step_ptr)
8428  PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_sz.x + style.ItemInnerSpacing.x)*2));
8429 
8430  char buf[64];
8431  DataTypeFormatString(data_type, data_ptr, scalar_format, buf, IM_ARRAYSIZE(buf));
8432 
8433  bool value_changed = false;
8434  if (!(extra_flags & ImGuiInputTextFlags_CharsHexadecimal))
8435  extra_flags |= ImGuiInputTextFlags_CharsDecimal;
8436  extra_flags |= ImGuiInputTextFlags_AutoSelectAll;
8437  if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags)) // PushId(label) + "" gives us the expected ID from outside point of view
8438  value_changed = DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format);
8439 
8440  // Step buttons
8441  if (step_ptr)
8442  {
8443  PopItemWidth();
8444  SameLine(0, style.ItemInnerSpacing.x);
8446  {
8447  DataTypeApplyOp(data_type, '-', data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
8448  value_changed = true;
8449  }
8450  SameLine(0, style.ItemInnerSpacing.x);
8452  {
8453  DataTypeApplyOp(data_type, '+', data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
8454  value_changed = true;
8455  }
8456  }
8457  PopID();
8458 
8459  if (label_size.x > 0)
8460  {
8461  SameLine(0, style.ItemInnerSpacing.x);
8462  RenderText(ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + style.FramePadding.y), label);
8463  ItemSize(label_size, style.FramePadding.y);
8464  }
8465  EndGroup();
8466 
8467  return value_changed;
8468 }
8469 
8470 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags)
8471 {
8472  char display_format[16];
8473  if (decimal_precision < 0)
8474  strcpy(display_format, "%f"); // Ideally we'd have a minimum decimal precision of 1 to visually denote that this is a float, while hiding non-significant digits? %f doesn't have a minimum of 1
8475  else
8476  ImFormatString(display_format, IM_ARRAYSIZE(display_format), "%%.%df", decimal_precision);
8477  return InputScalarEx(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), display_format, extra_flags);
8478 }
8479 
8480 bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags)
8481 {
8482  // 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.
8483  const char* scalar_format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
8484  return InputScalarEx(label, ImGuiDataType_Int, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), scalar_format, extra_flags);
8485 }
8486 
8487 bool ImGui::InputFloatN(const char* label, float* v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags)
8488 {
8489  ImGuiWindow* window = GetCurrentWindow();
8490  if (window->SkipItems)
8491  return false;
8492 
8493  ImGuiContext& g = *GImGui;
8494  bool value_changed = false;
8495  BeginGroup();
8496  PushID(label);
8497  PushMultiItemsWidths(components);
8498  for (int i = 0; i < components; i++)
8499  {
8500  PushID(i);
8501  value_changed |= InputFloat("##v", &v[i], 0, 0, decimal_precision, extra_flags);
8503  PopID();
8504  PopItemWidth();
8505  }
8506  PopID();
8507 
8509  TextUnformatted(label, FindRenderedTextEnd(label));
8510  EndGroup();
8511 
8512  return value_changed;
8513 }
8514 
8515 bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags)
8516 {
8517  return InputFloatN(label, v, 2, decimal_precision, extra_flags);
8518 }
8519 
8520 bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags)
8521 {
8522  return InputFloatN(label, v, 3, decimal_precision, extra_flags);
8523 }
8524 
8525 bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags)
8526 {
8527  return InputFloatN(label, v, 4, decimal_precision, extra_flags);
8528 }
8529 
8530 bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags)
8531 {
8532  ImGuiWindow* window = GetCurrentWindow();
8533  if (window->SkipItems)
8534  return false;
8535 
8536  ImGuiContext& g = *GImGui;
8537  bool value_changed = false;
8538  BeginGroup();
8539  PushID(label);
8540  PushMultiItemsWidths(components);
8541  for (int i = 0; i < components; i++)
8542  {
8543  PushID(i);
8544  value_changed |= InputInt("##v", &v[i], 0, 0, extra_flags);
8546  PopID();
8547  PopItemWidth();
8548  }
8549  PopID();
8550 
8552  TextUnformatted(label, FindRenderedTextEnd(label));
8553  EndGroup();
8554 
8555  return value_changed;
8556 }
8557 
8558 bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags)
8559 {
8560  return InputIntN(label, v, 2, extra_flags);
8561 }
8562 
8563 bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags)
8564 {
8565  return InputIntN(label, v, 3, extra_flags);
8566 }
8567 
8568 bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags)
8569 {
8570  return InputIntN(label, v, 4, extra_flags);
8571 }
8572 
8573 static bool Items_ArrayGetter(void* data, int idx, const char** out_text)
8574 {
8575  const char* const* items = (const char* const*)data;
8576  if (out_text)
8577  *out_text = items[idx];
8578  return true;
8579 }
8580 
8581 static bool Items_SingleStringGetter(void* data, int idx, const char** out_text)
8582 {
8583  // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited.
8584  const char* items_separated_by_zeros = (const char*)data;
8585  int items_count = 0;
8586  const char* p = items_separated_by_zeros;
8587  while (*p)
8588  {
8589  if (idx == items_count)
8590  break;
8591  p += strlen(p) + 1;
8592  items_count++;
8593  }
8594  if (!*p)
8595  return false;
8596  if (out_text)
8597  *out_text = p;
8598  return true;
8599 }
8600 
8601 // Combo box helper allowing to pass an array of strings.
8602 bool ImGui::Combo(const char* label, int* current_item, const char* const* items, int items_count, int height_in_items)
8603 {
8604  const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items);
8605  return value_changed;
8606 }
8607 
8608 // Combo box helper allowing to pass all items in a single string.
8609 bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items)
8610 {
8611  int items_count = 0;
8612  const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open
8613  while (*p)
8614  {
8615  p += strlen(p) + 1;
8616  items_count++;
8617  }
8618  bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items);
8619  return value_changed;
8620 }
8621 
8622 bool ImGui::BeginCombo(const char* label, const char* preview_value, ImVec2 popup_size)
8623 {
8624  ImGuiWindow* window = GetCurrentWindow();
8625  if (window->SkipItems)
8626  return false;
8627 
8628  ImGuiContext& g = *GImGui;
8629  const ImGuiStyle& style = g.Style;
8630  const ImGuiID id = window->GetID(label);
8631  const float w = CalcItemWidth();
8632 
8633  const ImVec2 label_size = CalcTextSize(label, NULL, true);
8634  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
8635  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));
8636  ItemSize(total_bb, style.FramePadding.y);
8637  if (!ItemAdd(total_bb, &id))
8638  return false;
8639 
8640  const float arrow_size = SmallSquareSize();
8641 
8642  bool hovered, held;
8643  bool pressed = ButtonBehavior(frame_bb, id, &hovered, &held);
8644 
8645  bool popup_open = IsPopupOpen(id);
8646 
8647  const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f));
8648  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
8649  RenderFrame(ImVec2(frame_bb.Max.x-arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32(popup_open || hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING
8650  RenderCollapseTriangle(ImVec2(frame_bb.Max.x - arrow_size + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), true);
8651 
8652  if (preview_value != NULL)
8653  RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, preview_value, NULL, NULL, ImVec2(0.0f,0.0f));
8654 
8655  if (label_size.x > 0)
8656  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
8657 
8658  if (pressed && !popup_open)
8659  {
8660  OpenPopupEx(id, false);
8661  popup_open = true;
8662  }
8663 
8664  if (!popup_open)
8665  return false;
8666 
8667  if (popup_size.x == 0.0f)
8668  popup_size.x = w;
8669 
8670  float popup_y1 = frame_bb.Max.y;
8671  float popup_y2 = ImClamp(popup_y1 + popup_size.y, popup_y1, g.IO.DisplaySize.y - style.DisplaySafeAreaPadding.y);
8672  if ((popup_y2 - popup_y1) < ImMin(popup_size.y, frame_bb.Min.y - style.DisplaySafeAreaPadding.y))
8673  {
8674  // Position our combo ABOVE because there's more space to fit! (FIXME: Handle in Begin() or use a shared helper. We have similar code in Begin() for popup placement)
8675  popup_y1 = ImClamp(frame_bb.Min.y - popup_size.y, style.DisplaySafeAreaPadding.y, frame_bb.Min.y);
8676  popup_y2 = frame_bb.Min.y;
8677  SetNextWindowPos(ImVec2(frame_bb.Min.x, frame_bb.Min.y), ImGuiCond_Always, ImVec2(0.0f, 1.0f));
8678  }
8679  else
8680  {
8681  // Position our combo below
8682  SetNextWindowPos(ImVec2(frame_bb.Min.x, frame_bb.Max.y), ImGuiCond_Always, ImVec2(0.0f, 0.0f));
8683  }
8684  SetNextWindowSize(ImVec2(popup_size.x, popup_y2 - popup_y1), ImGuiCond_Appearing);
8686 
8688  if (!BeginPopupEx(id, flags))
8689  {
8690  IM_ASSERT(0); // This should never happen as we tested for IsPopupOpen() above
8691  return false;
8692  }
8693  Spacing();
8694 
8695  return true;
8696 }
8697 
8699 {
8700  EndPopup();
8701  PopStyleVar();
8702 }
8703 
8704 // Combo box function.
8705 bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items)
8706 {
8707  ImGuiContext& g = *GImGui;
8708  const ImGuiStyle& style = g.Style;
8709 
8710  const char* preview_text = NULL;
8711  if (*current_item >= 0 && *current_item < items_count)
8712  items_getter(data, *current_item, &preview_text);
8713 
8714  // Size default to hold ~7 items
8715  if (height_in_items < 0)
8716  height_in_items = 7;
8717  float popup_height = (g.FontSize + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + (style.FramePadding.y * 3);
8718 
8719  if (!BeginCombo(label, preview_text, ImVec2(0.0f, popup_height)))
8720  return false;
8721 
8722  // Display items
8723  // FIXME-OPT: Use clipper
8724  bool value_changed = false;
8725  for (int i = 0; i < items_count; i++)
8726  {
8727  PushID((void*)(intptr_t)i);
8728  const bool item_selected = (i == *current_item);
8729  const char* item_text;
8730  if (!items_getter(data, i, &item_text))
8731  item_text = "*Unknown item*";
8732  if (Selectable(item_text, item_selected))
8733  {
8734  value_changed = true;
8735  *current_item = i;
8736  }
8737  if (item_selected && IsWindowAppearing())
8738  SetScrollHere();
8739  PopID();
8740  }
8741 
8742  EndCombo();
8743  return value_changed;
8744 }
8745 
8746 // Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image.
8747 // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID.
8748 bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
8749 {
8750  ImGuiWindow* window = GetCurrentWindow();
8751  if (window->SkipItems)
8752  return false;
8753 
8754  ImGuiContext& g = *GImGui;
8755  const ImGuiStyle& style = g.Style;
8756 
8757  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1) // FIXME-OPT: Avoid if vertically clipped.
8758  PopClipRect();
8759 
8760  ImGuiID id = window->GetID(label);
8761  ImVec2 label_size = CalcTextSize(label, NULL, true);
8762  ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
8763  ImVec2 pos = window->DC.CursorPos;
8764  pos.y += window->DC.CurrentLineTextBaseOffset;
8765  ImRect bb(pos, pos + size);
8766  ItemSize(bb);
8767 
8768  // Fill horizontal space.
8769  ImVec2 window_padding = window->WindowPadding;
8771  float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x);
8772  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);
8773  ImRect bb_with_spacing(pos, pos + size_draw);
8774  if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth))
8775  bb_with_spacing.Max.x += window_padding.x;
8776 
8777  // Selectables are tightly packed together, we extend the box to cover spacing between selectable.
8778  float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f);
8779  float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f);
8780  float spacing_R = style.ItemSpacing.x - spacing_L;
8781  float spacing_D = style.ItemSpacing.y - spacing_U;
8782  bb_with_spacing.Min.x -= spacing_L;
8783  bb_with_spacing.Min.y -= spacing_U;
8784  bb_with_spacing.Max.x += spacing_R;
8785  bb_with_spacing.Max.y += spacing_D;
8786  if (!ItemAdd(bb_with_spacing, &id))
8787  {
8788  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
8790  return false;
8791  }
8792 
8793  ImGuiButtonFlags button_flags = 0;
8794  if (flags & ImGuiSelectableFlags_Menu) button_flags |= ImGuiButtonFlags_PressedOnClick;
8796  if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled;
8798  bool hovered, held;
8799  bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags);
8800  if (flags & ImGuiSelectableFlags_Disabled)
8801  selected = false;
8802 
8803  // Render
8804  if (hovered || selected)
8805  {
8806  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
8807  RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, 0.0f);
8808  }
8809 
8810  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
8811  {
8813  bb_with_spacing.Max.x -= (GetContentRegionMax().x - max_x);
8814  }
8815 
8816  if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
8817  RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size, ImVec2(0.0f,0.0f));
8818  if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor();
8819 
8820  // Automatically close popups
8823  return pressed;
8824 }
8825 
8826 bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
8827 {
8828  if (Selectable(label, *p_selected, flags, size_arg))
8829  {
8830  *p_selected = !*p_selected;
8831  return true;
8832  }
8833  return false;
8834 }
8835 
8836 // Helper to calculate the size of a listbox and display a label on the right.
8837 // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an empty label "##empty"
8838 bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
8839 {
8840  ImGuiWindow* window = GetCurrentWindow();
8841  if (window->SkipItems)
8842  return false;
8843 
8844  const ImGuiStyle& style = GetStyle();
8845  const ImGuiID id = GetID(label);
8846  const ImVec2 label_size = CalcTextSize(label, NULL, true);
8847 
8848  // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
8849  ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y);
8850  ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));
8851  ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
8852  ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
8853  window->DC.LastItemRect = bb;
8854 
8855  BeginGroup();
8856  if (label_size.x > 0)
8857  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
8858 
8859  BeginChildFrame(id, frame_bb.GetSize());
8860  return true;
8861 }
8862 
8863 bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items)
8864 {
8865  // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
8866  // 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.
8867  // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution.
8868  if (height_in_items < 0)
8869  height_in_items = ImMin(items_count, 7);
8870  float height_in_items_f = height_in_items < items_count ? (height_in_items + 0.40f) : (height_in_items + 0.00f);
8871 
8872  // 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().
8873  ImVec2 size;
8874  size.x = 0.0f;
8875  size.y = GetTextLineHeightWithSpacing() * height_in_items_f + GetStyle().ItemSpacing.y;
8876  return ListBoxHeader(label, size);
8877 }
8878 
8880 {
8881  ImGuiWindow* parent_window = GetParentWindow();
8882  const ImRect bb = parent_window->DC.LastItemRect;
8883  const ImGuiStyle& style = GetStyle();
8884 
8885  EndChildFrame();
8886 
8887  // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect)
8888  // We call SameLine() to restore DC.CurrentLine* data
8889  SameLine();
8890  parent_window->DC.CursorPos = bb.Min;
8891  ItemSize(bb, style.FramePadding.y);
8892  EndGroup();
8893 }
8894 
8895 bool ImGui::ListBox(const char* label, int* current_item, const char* const* items, int items_count, int height_items)
8896 {
8897  const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items);
8898  return value_changed;
8899 }
8900 
8901 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)
8902 {
8903  if (!ListBoxHeader(label, items_count, height_in_items))
8904  return false;
8905 
8906  // 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.
8907  bool value_changed = false;
8908  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.
8909  while (clipper.Step())
8910  for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
8911  {
8912  const bool item_selected = (i == *current_item);
8913  const char* item_text;
8914  if (!items_getter(data, i, &item_text))
8915  item_text = "*Unknown item*";
8916 
8917  PushID(i);
8918  if (Selectable(item_text, item_selected))
8919  {
8920  *current_item = i;
8921  value_changed = true;
8922  }
8923  PopID();
8924  }
8925  ListBoxFooter();
8926  return value_changed;
8927 }
8928 
8929 bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled)
8930 {
8931  ImGuiWindow* window = GetCurrentWindow();
8932  if (window->SkipItems)
8933  return false;
8934 
8935  ImGuiContext& g = *GImGui;
8936  ImVec2 pos = window->DC.CursorPos;
8937  ImVec2 label_size = CalcTextSize(label, NULL, true);
8938  ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f);
8939  float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame
8940  float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
8941 
8943  if (shortcut_size.x > 0.0f)
8944  {
8946  RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false);
8947  PopStyleColor();
8948  }
8949 
8950  if (selected)
8951  RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled));
8952 
8953  return pressed;
8954 }
8955 
8956 bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled)
8957 {
8958  if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled))
8959  {
8960  if (p_selected)
8961  *p_selected = !*p_selected;
8962  return true;
8963  }
8964  return false;
8965 }
8966 
8968 {
8969  ImGuiContext& g = *GImGui;
8970  SetNextWindowPos(ImVec2(0.0f, 0.0f));
8975  || !BeginMenuBar())
8976  {
8977  End();
8978  PopStyleVar(2);
8979  return false;
8980  }
8982  return true;
8983 }
8984 
8986 {
8987  EndMenuBar();
8988  End();
8989  PopStyleVar(2);
8990 }
8991 
8993 {
8994  ImGuiWindow* window = GetCurrentWindow();
8995  if (window->SkipItems)
8996  return false;
8997  if (!(window->Flags & ImGuiWindowFlags_MenuBar))
8998  return false;
8999 
9000  IM_ASSERT(!window->DC.MenuBarAppending);
9001  BeginGroup(); // Save position
9002  PushID("##menubar");
9003  ImRect rect = window->MenuBarRect();
9004  PushClipRect(ImVec2(ImFloor(rect.Min.x+0.5f), ImFloor(rect.Min.y + window->BorderSize + 0.5f)), ImVec2(ImFloor(rect.Max.x+0.5f), ImFloor(rect.Max.y+0.5f)), false);
9005  window->DC.CursorPos = ImVec2(rect.Min.x + window->DC.MenuBarOffsetX, rect.Min.y);// + g.Style.FramePadding.y);
9007  window->DC.MenuBarAppending = true;
9009  return true;
9010 }
9011 
9013 {
9014  ImGuiWindow* window = GetCurrentWindow();
9015  if (window->SkipItems)
9016  return;
9017 
9019  IM_ASSERT(window->DC.MenuBarAppending);
9020  PopClipRect();
9021  PopID();
9022  window->DC.MenuBarOffsetX = window->DC.CursorPos.x - window->MenuBarRect().Min.x;
9023  window->DC.GroupStack.back().AdvanceCursor = false;
9024  EndGroup();
9026  window->DC.MenuBarAppending = false;
9027 }
9028 
9029 bool ImGui::BeginMenu(const char* label, bool enabled)
9030 {
9031  ImGuiWindow* window = GetCurrentWindow();
9032  if (window->SkipItems)
9033  return false;
9034 
9035  ImGuiContext& g = *GImGui;
9036  const ImGuiStyle& style = g.Style;
9037  const ImGuiID id = window->GetID(label);
9038 
9039  ImVec2 label_size = CalcTextSize(label, NULL, true);
9040 
9041  bool pressed;
9042  bool menu_is_open = IsPopupOpen(id);
9043  bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentMenuSet == window->GetID("##menus"));
9044  ImGuiWindow* backed_nav_window = g.NavWindow;
9045  if (menuset_is_open)
9046  g.NavWindow = window; // Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent)
9047 
9048  // The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu (using FindBestPopupWindowPos).
9049  ImVec2 popup_pos, pos = window->DC.CursorPos;
9050  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
9051  {
9052  // Menu inside an horizontal menu bar
9053  // Selectable extend their highlight by half ItemSpacing in each direction.
9054  popup_pos = ImVec2(pos.x - window->WindowPadding.x, pos.y - style.FramePadding.y + window->MenuBarHeight());
9055  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
9057  float w = label_size.x;
9058  pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
9059  PopStyleVar();
9060  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().
9061  }
9062  else
9063  {
9064  // Menu inside a menu
9065  popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
9066  float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame
9067  float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
9070  RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false);
9071  if (!enabled) PopStyleColor();
9072  }
9073 
9074  const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id);
9075  if (menuset_is_open)
9076  g.NavWindow = backed_nav_window;
9077 
9078  bool want_open = false, want_close = false;
9080  {
9081  // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
9082  bool moving_within_opened_triangle = false;
9083  if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window)
9084  {
9085  if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window)
9086  {
9087  ImRect next_window_rect = next_window->Rect();
9088  ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
9089  ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR();
9090  ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR();
9091  float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack.
9092  ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues
9093  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?
9094  tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f);
9095  moving_within_opened_triangle = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);
9096  //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
9097  }
9098  }
9099 
9100  want_close = (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle);
9101  want_open = (!menu_is_open && hovered && !moving_within_opened_triangle) || (!menu_is_open && hovered && pressed);
9102  }
9103  else if (menu_is_open && pressed && menuset_is_open) // Menu bar: click an open menu again to close it
9104  {
9105  want_close = true;
9106  want_open = menu_is_open = false;
9107  }
9108  else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // menu-bar: first click to open, then hover to open others
9109  {
9110  want_open = true;
9111  }
9112 
9113  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.. }'
9114  want_close = true;
9115  if (want_close && IsPopupOpen(id))
9116  ClosePopupToLevel(GImGui->CurrentPopupStack.Size);
9117 
9118  if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size)
9119  {
9120  // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame.
9121  OpenPopup(label);
9122  return false;
9123  }
9124 
9125  menu_is_open |= want_open;
9126  if (want_open)
9127  OpenPopup(label);
9128 
9129  if (menu_is_open)
9130  {
9131  SetNextWindowPos(popup_pos, ImGuiCond_Always);
9133  menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
9134  }
9135 
9136  return menu_is_open;
9137 }
9138 
9140 {
9141  EndPopup();
9142 }
9143 
9144 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
9145 void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags flags)
9146 {
9147  ImGuiContext& g = *GImGui;
9148 
9149  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]);
9150  BeginTooltipEx(0, true);
9151 
9152  const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;
9153  if (text_end > text)
9154  {
9155  TextUnformatted(text, text_end);
9156  Separator();
9157  }
9158 
9159  ImVec2 sz(g.FontSize * 3, g.FontSize * 3);
9161  SameLine();
9162  if (flags & ImGuiColorEditFlags_NoAlpha)
9163  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]);
9164  else
9165  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]);
9166  EndTooltip();
9167 }
9168 
9169 static inline ImU32 ImAlphaBlendColor(ImU32 col_a, ImU32 col_b)
9170 {
9171  float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
9172  int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
9173  int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
9174  int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
9175  return IM_COL32(r, g, b, 0xFF);
9176 }
9177 
9178 // 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.
9179 // 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.
9180 void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 col, float grid_step, ImVec2 grid_off, float rounding, int rounding_corners_flags)
9181 {
9182  ImGuiWindow* window = GetCurrentWindow();
9183  if (((col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT) < 0xFF)
9184  {
9185  ImU32 col_bg1 = GetColorU32(ImAlphaBlendColor(IM_COL32(204,204,204,255), col));
9186  ImU32 col_bg2 = GetColorU32(ImAlphaBlendColor(IM_COL32(128,128,128,255), col));
9187  window->DrawList->AddRectFilled(p_min, p_max, col_bg1, rounding, rounding_corners_flags);
9188 
9189  int yi = 0;
9190  for (float y = p_min.y + grid_off.y; y < p_max.y; y += grid_step, yi++)
9191  {
9192  float y1 = ImClamp(y, p_min.y, p_max.y), y2 = ImMin(y + grid_step, p_max.y);
9193  if (y2 <= y1)
9194  continue;
9195  for (float x = p_min.x + grid_off.x + (yi & 1) * grid_step; x < p_max.x; x += grid_step * 2.0f)
9196  {
9197  float x1 = ImClamp(x, p_min.x, p_max.x), x2 = ImMin(x + grid_step, p_max.x);
9198  if (x2 <= x1)
9199  continue;
9200  int rounding_corners_flags_cell = 0;
9201  if (y1 <= p_min.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImGuiCorner_TopLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImGuiCorner_TopRight; }
9202  if (y2 >= p_max.y) { if (x1 <= p_min.x) rounding_corners_flags_cell |= ImGuiCorner_BotLeft; if (x2 >= p_max.x) rounding_corners_flags_cell |= ImGuiCorner_BotRight; }
9203  rounding_corners_flags_cell &= rounding_corners_flags;
9204  window->DrawList->AddRectFilled(ImVec2(x1,y1), ImVec2(x2,y2), col_bg2, rounding_corners_flags_cell ? rounding : 0.0f, rounding_corners_flags_cell);
9205  }
9206  }
9207  }
9208  else
9209  {
9210  window->DrawList->AddRectFilled(p_min, p_max, col, rounding, rounding_corners_flags);
9211  }
9212 }
9213 
9215 {
9216  ImGuiContext& g = *GImGui;
9217  if ((flags & ImGuiColorEditFlags__InputsMask) == 0)
9219  if ((flags & ImGuiColorEditFlags__DataTypeMask) == 0)
9221  if ((flags & ImGuiColorEditFlags__PickerMask) == 0)
9223  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__InputsMask))); // Check only 1 option is selected
9224  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__DataTypeMask))); // Check only 1 option is selected
9225  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check only 1 option is selected
9226  g.ColorEditOptions = flags;
9227 }
9228 
9229 // A little colored square. Return true when clicked.
9230 // FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip.
9231 // 'desc_id' is not called 'label' because we don't display it next to the button, but only in the tooltip.
9232 bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFlags flags, ImVec2 size)
9233 {
9234  ImGuiWindow* window = GetCurrentWindow();
9235  if (window->SkipItems)
9236  return false;
9237 
9238  ImGuiContext& g = *GImGui;
9239  const ImGuiID id = window->GetID(desc_id);
9240  float default_size = SmallSquareSize();
9241  if (size.x == 0.0f)
9242  size.x = default_size;
9243  if (size.y == 0.0f)
9244  size.y = default_size;
9245  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
9246  ItemSize(bb);
9247  if (!ItemAdd(bb, &id))
9248  return false;
9249 
9250  bool hovered, held;
9251  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
9252 
9253  if (flags & ImGuiColorEditFlags_NoAlpha)
9255 
9256  ImVec4 col_without_alpha(col.x, col.y, col.z, 1.0f);
9257  float grid_step = ImMin(size.x, size.y) / 2.99f;
9258  float rounding = ImMin(g.Style.FrameRounding, grid_step * 0.5f);
9259  if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col.w < 1.0f)
9260  {
9261  float mid_x = (float)(int)((bb.Min.x + bb.Max.x) * 0.5f + 0.5f);
9262  RenderColorRectWithAlphaCheckerboard(ImVec2(bb.Min.x + grid_step, bb.Min.y), bb.Max, GetColorU32(col), grid_step, ImVec2(-grid_step, 0.0f), rounding, ImGuiCorner_TopRight|ImGuiCorner_BotRight);
9263  window->DrawList->AddRectFilled(bb.Min, ImVec2(mid_x, bb.Max.y), GetColorU32(col_without_alpha), rounding, ImGuiCorner_TopLeft|ImGuiCorner_BotLeft);
9264  }
9265  else
9266  {
9267  RenderColorRectWithAlphaCheckerboard(bb.Min, bb.Max, GetColorU32((flags & ImGuiColorEditFlags_AlphaPreview) ? col : col_without_alpha), grid_step, ImVec2(0,0), rounding);
9268  }
9269  if (window->Flags & ImGuiWindowFlags_ShowBorders)
9270  RenderFrameBorder(bb.Min, bb.Max, rounding);
9271  else
9272  window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding); // Color button are often in need of some sort of border
9273 
9274  if (hovered && !(flags & ImGuiColorEditFlags_NoTooltip))
9275  ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
9276 
9277  return pressed;
9278 }
9279 
9280 bool ImGui::ColorEdit3(const char* label, float col[3], ImGuiColorEditFlags flags)
9281 {
9282  return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha);
9283 }
9284 
9286 {
9287  bool allow_opt_inputs = !(flags & ImGuiColorEditFlags__InputsMask);
9288  bool allow_opt_datatype = !(flags & ImGuiColorEditFlags__DataTypeMask);
9289  if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context"))
9290  return;
9291  ImGuiContext& g = *GImGui;
9293  if (allow_opt_inputs)
9294  {
9295  if (RadioButton("RGB", (opts & ImGuiColorEditFlags_RGB) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_RGB;
9296  if (RadioButton("HSV", (opts & ImGuiColorEditFlags_HSV) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_HSV;
9297  if (RadioButton("HEX", (opts & ImGuiColorEditFlags_HEX) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__InputsMask) | ImGuiColorEditFlags_HEX;
9298  }
9299  if (allow_opt_datatype)
9300  {
9301  if (allow_opt_inputs) Separator();
9302  if (RadioButton("0..255", (opts & ImGuiColorEditFlags_Uint8) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Uint8;
9303  if (RadioButton("0.00..1.00", (opts & ImGuiColorEditFlags_Float) ? 1 : 0)) opts = (opts & ~ImGuiColorEditFlags__DataTypeMask) | ImGuiColorEditFlags_Float;
9304  }
9305 
9306  if (allow_opt_inputs || allow_opt_datatype)
9307  Separator();
9308  if (Button("Copy as..", ImVec2(-1,0)))
9309  OpenPopup("Copy");
9310  if (BeginPopup("Copy"))
9311  {
9312  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]);
9313  char buf[64];
9314  sprintf(buf, "(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
9315  if (Selectable(buf))
9316  SetClipboardText(buf);
9317  sprintf(buf, "(%d,%d,%d,%d)", cr, cg, cb, ca);
9318  if (Selectable(buf))
9319  SetClipboardText(buf);
9320  if (flags & ImGuiColorEditFlags_NoAlpha)
9321  sprintf(buf, "0x%02X%02X%02X", cr, cg, cb);
9322  else
9323  sprintf(buf, "0x%02X%02X%02X%02X", cr, cg, cb, ca);
9324  if (Selectable(buf))
9325  SetClipboardText(buf);
9326  EndPopup();
9327  }
9328 
9329  g.ColorEditOptions = opts;
9330  EndPopup();
9331 }
9332 
9333 static void ColorPickerOptionsPopup(ImGuiColorEditFlags flags, float* ref_col)
9334 {
9335  bool allow_opt_picker = !(flags & ImGuiColorEditFlags__PickerMask);
9336  bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar);
9337  if ((!allow_opt_picker && !allow_opt_alpha_bar) || !ImGui::BeginPopup("context"))
9338  return;
9339  ImGuiContext& g = *GImGui;
9340  if (allow_opt_picker)
9341  {
9342  ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (SmallSquareSize() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function
9343  ImGui::PushItemWidth(picker_size.x);
9344  for (int picker_type = 0; picker_type < 2; picker_type++)
9345  {
9346  // Draw small/thumbnail version of each picker type (over an invisible button for selection)
9347  if (picker_type > 0) ImGui::Separator();
9348  ImGui::PushID(picker_type);
9350  if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar;
9351  if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel;
9352  ImVec2 backup_pos = ImGui::GetCursorScreenPos();
9353  if (ImGui::Selectable("##selectable", false, 0, picker_size)) // By default, Selectable() is closing popup
9355  ImGui::SetCursorScreenPos(backup_pos);
9356  ImVec4 dummy_ref_col;
9357  memcpy(&dummy_ref_col.x, ref_col, sizeof(float) * (picker_flags & ImGuiColorEditFlags_NoAlpha ? 3 : 4));
9358  ImGui::ColorPicker4("##dummypicker", &dummy_ref_col.x, picker_flags);
9359  ImGui::PopID();
9360  }
9362  }
9363  if (allow_opt_alpha_bar)
9364  {
9365  if (allow_opt_picker) ImGui::Separator();
9366  ImGui::CheckboxFlags("Alpha Bar", (unsigned int*)&g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar);
9367  }
9368  ImGui::EndPopup();
9369 }
9370 
9371 // Edit colors components (each component in 0.0f..1.0f range).
9372 // See enum ImGuiColorEditFlags_ for available options. e.g. Only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
9373 // 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.
9374 bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags)
9375 {
9376  ImGuiWindow* window = GetCurrentWindow();
9377  if (window->SkipItems)
9378  return false;
9379 
9380  ImGuiContext& g = *GImGui;
9381  const ImGuiStyle& style = g.Style;
9382  const float square_sz = SmallSquareSize();
9383  const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
9384  const float w_items_all = CalcItemWidth() - w_extra;
9385  const char* label_display_end = FindRenderedTextEnd(label);
9386 
9387  const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0;
9388  const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0;
9389  const int components = alpha ? 4 : 3;
9390  const ImGuiColorEditFlags flags_untouched = flags;
9391 
9392  BeginGroup();
9393  PushID(label);
9394 
9395  // If we're not showing any slider there's no point in doing any HSV conversions
9396  if (flags & ImGuiColorEditFlags_NoInputs)
9398 
9399  // Context menu: display and modify options (before defaults are applied)
9400  if (!(flags & ImGuiColorEditFlags_NoOptions))
9401  ColorEditOptionsPopup(col, flags);
9402 
9403  // Read stored options
9404  if (!(flags & ImGuiColorEditFlags__InputsMask))
9405  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__InputsMask);
9406  if (!(flags & ImGuiColorEditFlags__DataTypeMask))
9407  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__DataTypeMask);
9408  if (!(flags & ImGuiColorEditFlags__PickerMask))
9409  flags |= (g.ColorEditOptions & ImGuiColorEditFlags__PickerMask);
9410  flags |= (g.ColorEditOptions & ~(ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask));
9411 
9412  // Convert to the formats we need
9413  float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f };
9414  if (flags & ImGuiColorEditFlags_HSV)
9415  ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
9417 
9418  bool value_changed = false;
9419  bool value_changed_as_float = false;
9420 
9421  if ((flags & (ImGuiColorEditFlags_RGB | ImGuiColorEditFlags_HSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
9422  {
9423  // RGB/HSV 0..255 Sliders
9424  const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
9425  const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
9426 
9427  const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
9428  const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
9429  const char* fmt_table_int[3][4] =
9430  {
9431  { "%3.0f", "%3.0f", "%3.0f", "%3.0f" }, // Short display
9432  { "R:%3.0f", "G:%3.0f", "B:%3.0f", "A:%3.0f" }, // Long display for RGBA
9433  { "H:%3.0f", "S:%3.0f", "V:%3.0f", "A:%3.0f" } // Long display for HSVA
9434  };
9435  const char* fmt_table_float[3][4] =
9436  {
9437  { "%0.3f", "%0.3f", "%0.3f", "%0.3f" }, // Short display
9438  { "R:%0.3f", "G:%0.3f", "B:%0.3f", "A:%0.3f" }, // Long display for RGBA
9439  { "H:%0.3f", "S:%0.3f", "V:%0.3f", "A:%0.3f" } // Long display for HSVA
9440  };
9441  const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_HSV) ? 2 : 1;
9442 
9443  PushItemWidth(w_item_one);
9444  for (int n = 0; n < components; n++)
9445  {
9446  if (n > 0)
9447  SameLine(0, style.ItemInnerSpacing.x);
9448  if (n + 1 == components)
9449  PushItemWidth(w_item_last);
9450  if (flags & ImGuiColorEditFlags_Float)
9451  value_changed |= value_changed_as_float |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
9452  else
9453  value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
9454  if (!(flags & ImGuiColorEditFlags_NoOptions) && IsItemHovered() && IsMouseClicked(1))
9455  OpenPopup("context");
9456  }
9457  PopItemWidth();
9458  PopItemWidth();
9459  }
9460  else if ((flags & ImGuiColorEditFlags_HEX) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
9461  {
9462  // RGB Hexadecimal Input
9463  char buf[64];
9464  if (alpha)
9465  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));
9466  else
9467  ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255));
9468  PushItemWidth(w_items_all);
9470  {
9471  value_changed |= true;
9472  char* p = buf;
9473  while (*p == '#' || ImCharIsSpace(*p))
9474  p++;
9475  i[0] = i[1] = i[2] = i[3] = 0;
9476  if (alpha)
9477  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)
9478  else
9479  sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]);
9480  }
9481  if (!(flags & ImGuiColorEditFlags_NoOptions) && IsItemHovered() && IsMouseClicked(1))
9482  OpenPopup("context");
9483  PopItemWidth();
9484  }
9485 
9486  bool picker_active = false;
9487  if (!(flags & ImGuiColorEditFlags_NoSmallPreview))
9488  {
9489  if (!(flags & ImGuiColorEditFlags_NoInputs))
9490  SameLine(0, style.ItemInnerSpacing.x);
9491 
9492  const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f);
9493  if (ColorButton("##ColorButton", col_v4, flags))
9494  {
9495  if (!(flags & ImGuiColorEditFlags_NoPicker))
9496  {
9497  // Store current color and open a picker
9498  g.ColorPickerRef = col_v4;
9499  OpenPopup("picker");
9500  SetNextWindowPos(window->DC.LastItemRect.GetBL() + ImVec2(-1,style.ItemSpacing.y));
9501  }
9502  }
9503  if (!(flags & ImGuiColorEditFlags_NoOptions) && IsItemHovered() && IsMouseClicked(1))
9504  OpenPopup("context");
9505 
9506  if (BeginPopup("picker"))
9507  {
9508  picker_active = true;
9509  if (label != label_display_end)
9510  {
9511  TextUnformatted(label, label_display_end);
9512  Separator();
9513  }
9514  ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
9515  ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags__InputsMask | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
9516  PushItemWidth(square_sz * 12.0f); // Use 256 + bar sizes?
9517  value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x);
9518  PopItemWidth();
9519  EndPopup();
9520  }
9521  }
9522 
9523  if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
9524  {
9525  SameLine(0, style.ItemInnerSpacing.x);
9526  TextUnformatted(label, label_display_end);
9527  }
9528 
9529  // Convert back
9530  if (!picker_active)
9531  {
9532  if (!value_changed_as_float)
9533  for (int n = 0; n < 4; n++)
9534  f[n] = i[n] / 255.0f;
9535  if (flags & ImGuiColorEditFlags_HSV)
9536  ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
9537  if (value_changed)
9538  {
9539  col[0] = f[0];
9540  col[1] = f[1];
9541  col[2] = f[2];
9542  if (alpha)
9543  col[3] = f[3];
9544  }
9545  }
9546 
9547  PopID();
9548  EndGroup();
9549 
9550  return value_changed;
9551 }
9552 
9553 bool ImGui::ColorPicker3(const char* label, float col[3], ImGuiColorEditFlags flags)
9554 {
9555  float col4[4] = { col[0], col[1], col[2], 1.0f };
9556  if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha))
9557  return false;
9558  col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2];
9559  return true;
9560 }
9561 
9562 // 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
9563 static void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
9564 {
9565  switch (direction)
9566  {
9567  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;
9568  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;
9569  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;
9570  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;
9571  default: return; // Fix warning for ImGuiDir_None
9572  }
9573 }
9574 
9575 static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w)
9576 {
9577  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);
9578  RenderArrow(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32_WHITE);
9579  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);
9580  RenderArrow(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32_WHITE);
9581 }
9582 
9583 static void PaintVertsLinearGradientKeepAlpha(ImDrawVert* vert_start, ImDrawVert* vert_end, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1)
9584 {
9585  ImVec2 gradient_extent = gradient_p1 - gradient_p0;
9586  float gradient_inv_length2 = 1.0f / ImLengthSqr(gradient_extent);
9587  for (ImDrawVert* vert = vert_start; vert < vert_end; vert++)
9588  {
9589  float d = ImDot(vert->pos - gradient_p0, gradient_extent);
9590  float t = ImClamp(d * gradient_inv_length2, 0.0f, 1.0f);
9591  int r = ImLerp((int)(col0 >> IM_COL32_R_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_R_SHIFT) & 0xFF, t);
9592  int g = ImLerp((int)(col0 >> IM_COL32_G_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_G_SHIFT) & 0xFF, t);
9593  int b = ImLerp((int)(col0 >> IM_COL32_B_SHIFT) & 0xFF, (int)(col1 >> IM_COL32_B_SHIFT) & 0xFF, t);
9594  vert->col = (r << IM_COL32_R_SHIFT) | (g << IM_COL32_G_SHIFT) | (b << IM_COL32_B_SHIFT) | (vert->col & IM_COL32_A_MASK);
9595  }
9596 }
9597 
9598 // ColorPicker
9599 // Note: only access 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
9600 // 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..)
9601 bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col)
9602 {
9603  ImGuiContext& g = *GImGui;
9604  ImGuiWindow* window = GetCurrentWindow();
9605  ImDrawList* draw_list = window->DrawList;
9606 
9607  ImGuiStyle& style = g.Style;
9608  ImGuiIO& io = g.IO;
9609 
9610  PushID(label);
9611  BeginGroup();
9612 
9613  if (!(flags & ImGuiColorEditFlags_NoSidePreview))
9615 
9616  // Context menu: display and store options.
9617  if (!(flags & ImGuiColorEditFlags_NoOptions))
9618  ColorPickerOptionsPopup(flags, col);
9619 
9620  // Read stored options
9621  if (!(flags & ImGuiColorEditFlags__PickerMask))
9623  IM_ASSERT(ImIsPowerOfTwo((int)(flags & ImGuiColorEditFlags__PickerMask))); // Check that only 1 is selected
9624  if (!(flags & ImGuiColorEditFlags_NoOptions))
9626 
9627  // Setup
9628  bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha);
9629  ImVec2 picker_pos = window->DC.CursorPos;
9630  float square_sz = SmallSquareSize();
9631  float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars
9632  float sv_picker_size = ImMax(bars_width * 1, CalcItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box
9633  float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
9634  float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
9635  float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f);
9636 
9637  float wheel_thickness = sv_picker_size * 0.08f;
9638  float wheel_r_outer = sv_picker_size * 0.50f;
9639  float wheel_r_inner = wheel_r_outer - wheel_thickness;
9640  ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size*0.5f);
9641 
9642  // Note: the triangle is displayed rotated with triangle_pa pointing to Hue, but most coordinates stays unrotated for logic.
9643  float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f);
9644  ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f); // Hue point.
9645  ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f); // Black point.
9646  ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f); // White point.
9647 
9648  float H,S,V;
9649  ColorConvertRGBtoHSV(col[0], col[1], col[2], H, S, V);
9650 
9651  bool value_changed = false, value_changed_h = false, value_changed_sv = false;
9652 
9654  {
9655  // Hue wheel + SV triangle logic
9656  InvisibleButton("hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size));
9657  if (IsItemActive())
9658  {
9659  ImVec2 initial_off = g.IO.MouseClickedPos[0] - wheel_center;
9660  ImVec2 current_off = g.IO.MousePos - wheel_center;
9661  float initial_dist2 = ImLengthSqr(initial_off);
9662  if (initial_dist2 >= (wheel_r_inner-1)*(wheel_r_inner-1) && initial_dist2 <= (wheel_r_outer+1)*(wheel_r_outer+1))
9663  {
9664  // Interactive with Hue wheel
9665  H = atan2f(current_off.y, current_off.x) / IM_PI*0.5f;
9666  if (H < 0.0f)
9667  H += 1.0f;
9668  value_changed = value_changed_h = true;
9669  }
9670  float cos_hue_angle = cosf(-H * 2.0f * IM_PI);
9671  float sin_hue_angle = sinf(-H * 2.0f * IM_PI);
9672  if (ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle)))
9673  {
9674  // Interacting with SV triangle
9675  ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle);
9676  if (!ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated))
9677  current_off_unrotated = ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated);
9678  float uu, vv, ww;
9679  ImTriangleBarycentricCoords(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated, uu, vv, ww);
9680  V = ImClamp(1.0f - vv, 0.0001f, 1.0f);
9681  S = ImClamp(uu / V, 0.0001f, 1.0f);
9682  value_changed = value_changed_sv = true;
9683  }
9684  }
9685  if (!(flags & ImGuiColorEditFlags_NoOptions) && IsItemHovered() && IsMouseClicked(1))
9686  OpenPopup("context");
9687  }
9688  else if (flags & ImGuiColorEditFlags_PickerHueBar)
9689  {
9690  // SV rectangle logic
9691  InvisibleButton("sv", ImVec2(sv_picker_size, sv_picker_size));
9692  if (IsItemActive())
9693  {
9694  S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size-1));
9695  V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
9696  value_changed = value_changed_sv = true;
9697  }
9698  if (!(flags & ImGuiColorEditFlags_NoOptions) && IsItemHovered() && IsMouseClicked(1))
9699  OpenPopup("context");
9700 
9701  // Hue bar logic
9702  SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y));
9703  InvisibleButton("hue", ImVec2(bars_width, sv_picker_size));
9704  if (IsItemActive())
9705  {
9706  H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
9707  value_changed = value_changed_h = true;
9708  }
9709  }
9710 
9711  // Alpha bar logic
9712  if (alpha_bar)
9713  {
9714  SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y));
9715  InvisibleButton("alpha", ImVec2(bars_width, sv_picker_size));
9716  if (IsItemActive())
9717  {
9718  col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size-1));
9719  value_changed = true;
9720  }
9721  }
9722 
9723  if (!(flags & ImGuiColorEditFlags_NoSidePreview))
9724  {
9725  SameLine(0, style.ItemInnerSpacing.x);
9726  BeginGroup();
9727  }
9728 
9729  if (!(flags & ImGuiColorEditFlags_NoLabel))
9730  {
9731  const char* label_display_end = FindRenderedTextEnd(label);
9732  if (label != label_display_end)
9733  {
9734  if ((flags & ImGuiColorEditFlags_NoSidePreview))
9735  SameLine(0, style.ItemInnerSpacing.x);
9736  TextUnformatted(label, label_display_end);
9737  }
9738  }
9739 
9740  if (!(flags & ImGuiColorEditFlags_NoSidePreview))
9741  {
9742  ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
9743  if ((flags & ImGuiColorEditFlags_NoLabel))
9744  Text("Current");
9746  if (ref_col != NULL)
9747  {
9748  Text("Original");
9749  ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]);
9751  {
9752  memcpy(col, ref_col, ((flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4) * sizeof(float));
9753  value_changed = true;
9754  }
9755  }
9756  EndGroup();
9757  }
9758 
9759  // Convert back color to RGB
9760  if (value_changed_h || value_changed_sv)
9761  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]);
9762 
9763  // R,G,B and H,S,V slider color editor
9764  if ((flags & ImGuiColorEditFlags_NoInputs) == 0)
9765  {
9766  PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x);
9768  ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker;
9769  if (flags & ImGuiColorEditFlags_RGB || (flags & ImGuiColorEditFlags__InputsMask) == 0)
9770  value_changed |= ColorEdit4("##rgb", col, sub_flags | ImGuiColorEditFlags_RGB);
9771  if (flags & ImGuiColorEditFlags_HSV || (flags & ImGuiColorEditFlags__InputsMask) == 0)
9772  value_changed |= ColorEdit4("##hsv", col, sub_flags | ImGuiColorEditFlags_HSV);
9773  if (flags & ImGuiColorEditFlags_HEX || (flags & ImGuiColorEditFlags__InputsMask) == 0)
9774  value_changed |= ColorEdit4("##hex", col, sub_flags | ImGuiColorEditFlags_HEX);
9775  PopItemWidth();
9776  }
9777 
9778  // Try to cancel hue wrap (after ColorEdit), if any
9779  if (value_changed)
9780  {
9781  float new_H, new_S, new_V;
9782  ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V);
9783  if (new_H <= 0 && H > 0)
9784  {
9785  if (new_V <= 0 && V != new_V)
9786  ColorConvertHSVtoRGB(H, S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]);
9787  else if (new_S <= 0)
9788  ColorConvertHSVtoRGB(H, new_S <= 0 ? S * 0.5f : new_S, new_V, col[0], col[1], col[2]);
9789  }
9790  }
9791 
9792  ImVec4 hue_color_f(1, 1, 1, 1); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
9793  ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);
9794  ImU32 col32_no_alpha = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 1.0f));
9795 
9796  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) };
9797  ImVec2 sv_cursor_pos;
9798 
9799  if (flags & ImGuiColorEditFlags_PickerHueWheel)
9800  {
9801  // Render Hue Wheel
9802  const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).
9803  const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12);
9804  for (int n = 0; n < 6; n++)
9805  {
9806  const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps;
9807  const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps;
9808  int vert_start_idx = draw_list->_VtxCurrentIdx;
9809  draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc);
9810  draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness);
9811 
9812  // Paint colors over existing vertices
9813  ImVec2 gradient_p0(wheel_center.x + cosf(a0) * wheel_r_inner, wheel_center.y + sinf(a0) * wheel_r_inner);
9814  ImVec2 gradient_p1(wheel_center.x + cosf(a1) * wheel_r_inner, wheel_center.y + sinf(a1) * wheel_r_inner);
9815  PaintVertsLinearGradientKeepAlpha(draw_list->_VtxWritePtr - (draw_list->_VtxCurrentIdx - vert_start_idx), draw_list->_VtxWritePtr, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]);
9816  }
9817 
9818  // Render Cursor + preview on Hue Wheel
9819  float cos_hue_angle = cosf(H * 2.0f * IM_PI);
9820  float sin_hue_angle = sinf(H * 2.0f * IM_PI);
9821  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);
9822  float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;
9823  int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32);
9824  draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);
9825  draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, IM_COL32(128,128,128,255), hue_cursor_segments);
9826  draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments);
9827 
9828  // Render SV triangle (rotated according to hue)
9829  ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);
9830  ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle);
9831  ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle);
9832  ImVec2 uv_white = g.FontTexUvWhitePixel;
9833  draw_list->PrimReserve(6, 6);
9834  draw_list->PrimVtx(tra, uv_white, hue_color32);
9835  draw_list->PrimVtx(trb, uv_white, hue_color32);
9836  draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE);
9837  draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS);
9838  draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK);
9839  draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS);
9840  draw_list->AddTriangle(tra, trb, trc, IM_COL32(128,128,128,255), 1.5f);
9841  sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));
9842  }
9843  else if (flags & ImGuiColorEditFlags_PickerHueBar)
9844  {
9845  // Render SV Square
9846  draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE);
9847  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);
9848  RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), 0.0f);
9849  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
9850  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);
9851 
9852  // Render Hue Bar
9853  for (int i = 0; i < 6; ++i)
9854  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]);
9855  float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f);
9856  RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);
9857  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);
9858  }
9859 
9860  // Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range)
9861  float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f;
9862  draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, col32_no_alpha, 12);
9863  draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, IM_COL32(128,128,128,255), 12);
9864  draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, IM_COL32_WHITE, 12);
9865 
9866  // Render alpha bar
9867  if (alpha_bar)
9868  {
9869  float alpha = ImSaturate(col[3]);
9870  ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);
9871  RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, IM_COL32(0,0,0,0), bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
9872  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);
9873  float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f);
9874  RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);
9875  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);
9876  }
9877 
9878  EndGroup();
9879  PopID();
9880 
9881  return value_changed;
9882 }
9883 
9884 // Horizontal separating line.
9886 {
9887  ImGuiWindow* window = GetCurrentWindow();
9888  if (window->SkipItems)
9889  return;
9890  ImGuiContext& g = *GImGui;
9891 
9892  ImGuiWindowFlags flags = 0;
9895  IM_ASSERT(ImIsPowerOfTwo((int)(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)))); // Check that only 1 option is selected
9896  if (flags & ImGuiSeparatorFlags_Vertical)
9897  {
9899  return;
9900  }
9901 
9902  // Horizontal Separator
9903  if (window->DC.ColumnsCount > 1)
9904  PopClipRect();
9905 
9906  float x1 = window->Pos.x;
9907  float x2 = window->Pos.x + window->Size.x;
9908  if (!window->DC.GroupStack.empty())
9909  x1 += window->DC.IndentX;
9910 
9911  const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y+1.0f));
9912  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.
9913  if (!ItemAdd(bb, NULL))
9914  {
9915  if (window->DC.ColumnsCount > 1)
9917  return;
9918  }
9919 
9920  window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x,bb.Min.y), GetColorU32(ImGuiCol_Separator));
9921 
9922  if (g.LogEnabled)
9923  LogRenderedText(NULL, IM_NEWLINE "--------------------------------");
9924 
9925  if (window->DC.ColumnsCount > 1)
9926  {
9928  window->DC.ColumnsCellMinY = window->DC.CursorPos.y;
9929  }
9930 }
9931 
9933 {
9934  ImGuiWindow* window = GetCurrentWindow();
9935  if (window->SkipItems)
9936  return;
9937  ImGuiContext& g = *GImGui;
9938 
9939  float y1 = window->DC.CursorPos.y;
9940  float y2 = window->DC.CursorPos.y + window->DC.CurrentLineHeight;
9941  const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2));
9942  ItemSize(ImVec2(bb.GetWidth(), 0.0f));
9943  if (!ItemAdd(bb, NULL))
9944  return;
9945 
9946  window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator));
9947  if (g.LogEnabled)
9948  LogText(" |");
9949 }
9950 
9952 {
9953  ImGuiWindow* window = GetCurrentWindow();
9954  if (window->SkipItems)
9955  return;
9956  ItemSize(ImVec2(0,0));
9957 }
9958 
9959 void ImGui::Dummy(const ImVec2& size)
9960 {
9961  ImGuiWindow* window = GetCurrentWindow();
9962  if (window->SkipItems)
9963  return;
9964 
9965  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
9966  ItemSize(bb);
9967  ItemAdd(bb, NULL);
9968 }
9969 
9970 bool ImGui::IsRectVisible(const ImVec2& size)
9971 {
9972  ImGuiWindow* window = GetCurrentWindowRead();
9973  return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
9974 }
9975 
9976 bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
9977 {
9978  ImGuiWindow* window = GetCurrentWindowRead();
9979  return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
9980 }
9981 
9982 // 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.)
9984 {
9985  ImGuiWindow* window = GetCurrentWindow();
9986 
9987  window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
9988  ImGuiGroupData& group_data = window->DC.GroupStack.back();
9989  group_data.BackupCursorPos = window->DC.CursorPos;
9990  group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
9991  group_data.BackupIndentX = window->DC.IndentX;
9992  group_data.BackupGroupOffsetX = window->DC.GroupOffsetX;
9993  group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight;
9995  group_data.BackupLogLinePosY = window->DC.LogLinePosY;
9996  group_data.BackupActiveIdIsAlive = GImGui->ActiveIdIsAlive;
9997  group_data.AdvanceCursor = true;
9998 
9999  window->DC.GroupOffsetX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX;
10000  window->DC.IndentX = window->DC.GroupOffsetX;
10001  window->DC.CursorMaxPos = window->DC.CursorPos;
10002  window->DC.CurrentLineHeight = 0.0f;
10003  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
10004 }
10005 
10007 {
10008  ImGuiContext& g = *GImGui;
10009  ImGuiWindow* window = GetCurrentWindow();
10010 
10011  IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls
10012 
10013  ImGuiGroupData& group_data = window->DC.GroupStack.back();
10014 
10015  ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos);
10016  group_bb.Max.y -= g.Style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves.
10017  group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
10018 
10019  window->DC.CursorPos = group_data.BackupCursorPos;
10020  window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
10021  window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight;
10022  window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
10023  window->DC.IndentX = group_data.BackupIndentX;
10024  window->DC.GroupOffsetX = group_data.BackupGroupOffsetX;
10025  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
10026 
10027  if (group_data.AdvanceCursor)
10028  {
10029  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.
10030  ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset);
10031  ItemAdd(group_bb, NULL);
10032  }
10033 
10034  // 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.
10035  // 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.
10036  const bool active_id_within_group = (!group_data.BackupActiveIdIsAlive && g.ActiveIdIsAlive && g.ActiveId && g.ActiveIdWindow->RootWindow == window->RootWindow);
10037  if (active_id_within_group)
10038  window->DC.LastItemId = g.ActiveId;
10039  window->DC.LastItemRect = group_bb;
10040 
10041  window->DC.GroupStack.pop_back();
10042 
10043  //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
10044 }
10045 
10046 // Gets back to previous line and continue with horizontal layout
10047 // pos_x == 0 : follow right after previous item
10048 // pos_x != 0 : align to specified x position (relative to window/group left)
10049 // spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0
10050 // spacing_w >= 0 : enforce spacing amount
10051 void ImGui::SameLine(float pos_x, float spacing_w)
10052 {
10053  ImGuiWindow* window = GetCurrentWindow();
10054  if (window->SkipItems)
10055  return;
10056 
10057  ImGuiContext& g = *GImGui;
10058  if (pos_x != 0.0f)
10059  {
10060  if (spacing_w < 0.0f) spacing_w = 0.0f;
10061  window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffsetX + window->DC.ColumnsOffsetX;
10062  window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
10063  }
10064  else
10065  {
10066  if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
10067  window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
10068  window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
10069  }
10070  window->DC.CurrentLineHeight = window->DC.PrevLineHeight;
10072 }
10073 
10075 {
10076  ImGuiWindow* window = GetCurrentWindow();
10077  if (window->SkipItems)
10078  return;
10079 
10080  ImGuiContext& g = *GImGui;
10081  const ImGuiLayoutType backup_layout_type = window->DC.LayoutType;
10083  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.
10084  ItemSize(ImVec2(0,0));
10085  else
10086  ItemSize(ImVec2(0.0f, g.FontSize));
10087  window->DC.LayoutType = backup_layout_type;
10088 }
10089 
10091 {
10092  ImGuiWindow* window = GetCurrentWindow();
10093  if (window->SkipItems || window->DC.ColumnsCount <= 1)
10094  return;
10095 
10096  ImGuiContext& g = *GImGui;
10097  PopItemWidth();
10098  PopClipRect();
10099 
10100  window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
10101  if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount)
10102  {
10103  // Columns 1+ cancel out IndentX
10104  window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x;
10105  window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent);
10106  }
10107  else
10108  {
10109  window->DC.ColumnsCurrent = 0;
10110  window->DC.ColumnsOffsetX = 0.0f;
10111  window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY;
10112  window->DrawList->ChannelsSetCurrent(0);
10113  }
10114  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
10115  window->DC.CursorPos.y = window->DC.ColumnsCellMinY;
10116  window->DC.CurrentLineHeight = 0.0f;
10117  window->DC.CurrentLineTextBaseOffset = 0.0f;
10118 
10120  PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup
10121 }
10122 
10124 {
10125  ImGuiWindow* window = GetCurrentWindowRead();
10126  return window->DC.ColumnsCurrent;
10127 }
10128 
10130 {
10131  ImGuiWindow* window = GetCurrentWindowRead();
10132  return window->DC.ColumnsCount;
10133 }
10134 
10135 static float OffsetNormToPixels(ImGuiWindow* window, float offset_norm)
10136 {
10137  return offset_norm * (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
10138 }
10139 
10140 static float PixelsToOffsetNorm(ImGuiWindow* window, float offset)
10141 {
10142  return (offset - window->DC.ColumnsMinX) / (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
10143 }
10144 
10145 static float GetDraggedColumnOffset(int column_index)
10146 {
10147  // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
10148  // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
10149  ImGuiContext& g = *GImGui;
10151  IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets.
10152  IM_ASSERT(g.ActiveId == window->DC.ColumnsSetId + ImGuiID(column_index));
10153 
10154  float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x - window->Pos.x;
10155  x = ImMax(x, ImGui::GetColumnOffset(column_index-1) + g.Style.ColumnsMinSpacing);
10157  x = ImMin(x, ImGui::GetColumnOffset(column_index+1) - g.Style.ColumnsMinSpacing);
10158 
10159  return x;
10160 }
10161 
10162 float ImGui::GetColumnOffset(int column_index)
10163 {
10164  ImGuiWindow* window = GetCurrentWindowRead();
10165  if (column_index < 0)
10166  column_index = window->DC.ColumnsCurrent;
10167 
10168  /*
10169  if (g.ActiveId)
10170  {
10171  ImGuiContext& g = *GImGui;
10172  const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
10173  if (g.ActiveId == column_id)
10174  return GetDraggedColumnOffset(column_index);
10175  }
10176  */
10177 
10178  IM_ASSERT(column_index < window->DC.ColumnsData.Size);
10179  const float t = window->DC.ColumnsData[column_index].OffsetNorm;
10180  const float x_offset = ImLerp(window->DC.ColumnsMinX, window->DC.ColumnsMaxX, t);
10181  return x_offset;
10182 }
10183 
10184 void ImGui::SetColumnOffset(int column_index, float offset)
10185 {
10186  ImGuiContext& g = *GImGui;
10187  ImGuiWindow* window = GetCurrentWindow();
10188  if (column_index < 0)
10189  column_index = window->DC.ColumnsCurrent;
10190 
10191  IM_ASSERT(column_index < window->DC.ColumnsData.Size);
10192 
10193  const bool preserve_width = !(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < window->DC.ColumnsCount-1);
10194  const float width = preserve_width ? GetColumnWidth(column_index) : 0.0f;
10195 
10197  offset = ImMin(offset, window->DC.ColumnsMaxX - g.Style.ColumnsMinSpacing * (window->DC.ColumnsCount - column_index));
10198  const float offset_norm = PixelsToOffsetNorm(window, offset);
10199 
10200  const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
10201  window->DC.StateStorage->SetFloat(column_id, offset_norm);
10202  window->DC.ColumnsData[column_index].OffsetNorm = offset_norm;
10203 
10204  if (preserve_width)
10205  SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
10206 }
10207 
10208 float ImGui::GetColumnWidth(int column_index)
10209 {
10210  ImGuiWindow* window = GetCurrentWindowRead();
10211  if (column_index < 0)
10212  column_index = window->DC.ColumnsCurrent;
10213 
10214  return OffsetNormToPixels(window, window->DC.ColumnsData[column_index+1].OffsetNorm - window->DC.ColumnsData[column_index].OffsetNorm);
10215 }
10216 
10217 void ImGui::SetColumnWidth(int column_index, float width)
10218 {
10219  ImGuiWindow* window = GetCurrentWindowRead();
10220  if (column_index < 0)
10221  column_index = window->DC.ColumnsCurrent;
10222 
10223  SetColumnOffset(column_index+1, GetColumnOffset(column_index) + width);
10224 }
10225 
10226 void ImGui::PushColumnClipRect(int column_index)
10227 {
10228  ImGuiWindow* window = GetCurrentWindowRead();
10229  if (column_index < 0)
10230  column_index = window->DC.ColumnsCurrent;
10231 
10232  PushClipRect(window->DC.ColumnsData[column_index].ClipRect.Min, window->DC.ColumnsData[column_index].ClipRect.Max, false);
10233 }
10234 
10235 void ImGui::BeginColumns(const char* id, int columns_count, ImGuiColumnsFlags flags)
10236 {
10237  ImGuiContext& g = *GImGui;
10238  ImGuiWindow* window = GetCurrentWindow();
10239 
10240  IM_ASSERT(columns_count > 1);
10241  IM_ASSERT(window->DC.ColumnsCount == 1); // Nested columns are currently not supported
10242 
10243  // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
10244  // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
10245  PushID(0x11223347 + (id ? 0 : columns_count));
10246  window->DC.ColumnsSetId = window->GetID(id ? id : "columns");
10247  PopID();
10248 
10249  // Set state for first column
10250  window->DC.ColumnsCurrent = 0;
10251  window->DC.ColumnsCount = columns_count;
10252  window->DC.ColumnsFlags = flags;
10253 
10254  const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->Size.x -window->ScrollbarSizes.x);
10255  window->DC.ColumnsMinX = window->DC.IndentX - g.Style.ItemSpacing.x; // Lock our horizontal range
10256  //window->DC.ColumnsMaxX = content_region_width - window->Scroll.x -((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize);// - window->WindowPadding().x;
10257  window->DC.ColumnsMaxX = content_region_width - window->Scroll.x;
10258  window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
10259  window->DC.ColumnsStartMaxPosX = window->DC.CursorMaxPos.x;
10260  window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.CursorPos.y;
10261  window->DC.ColumnsOffsetX = 0.0f;
10262  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
10263 
10264  // Cache column offsets
10265  window->DC.ColumnsData.resize(columns_count + 1);
10266  for (int column_index = 0; column_index < columns_count + 1; column_index++)
10267  {
10268  const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(column_index);
10269  KeepAliveID(column_id);
10270  const float default_t = column_index / (float)window->DC.ColumnsCount;
10271  float t = window->DC.StateStorage->GetFloat(column_id, default_t);
10273  t = ImMin(t, PixelsToOffsetNorm(window, window->DC.ColumnsMaxX - g.Style.ColumnsMinSpacing * (window->DC.ColumnsCount - column_index)));
10274  window->DC.ColumnsData[column_index].OffsetNorm = t;
10275  }
10276 
10277  // Cache clipping rectangles
10278  for (int column_index = 0; column_index < columns_count; column_index++)
10279  {
10280  float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(column_index) - 1.0f);
10281  float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(column_index + 1) - 1.0f);
10282  window->DC.ColumnsData[column_index].ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
10283  window->DC.ColumnsData[column_index].ClipRect.ClipWith(window->ClipRect);
10284  }
10285 
10286  window->DrawList->ChannelsSplit(window->DC.ColumnsCount);
10288  PushItemWidth(GetColumnWidth() * 0.65f);
10289 }
10290 
10292 {
10293  ImGuiContext& g = *GImGui;
10294  ImGuiWindow* window = GetCurrentWindow();
10295  IM_ASSERT(window->DC.ColumnsCount > 1);
10296 
10297  PopItemWidth();
10298  PopClipRect();
10299  window->DrawList->ChannelsMerge();
10300 
10301  window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
10302  window->DC.CursorPos.y = window->DC.ColumnsCellMaxY;
10303  window->DC.CursorMaxPos.x = ImMax(window->DC.ColumnsStartMaxPosX, window->DC.ColumnsMaxX); // Columns don't grow parent
10304 
10305  // Draw columns borders and handle resize
10306  if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
10307  {
10308  const float y1 = window->DC.ColumnsStartPosY;
10309  const float y2 = window->DC.CursorPos.y;
10310  int dragging_column = -1;
10311  for (int i = 1; i < window->DC.ColumnsCount; i++)
10312  {
10313  float x = window->Pos.x + GetColumnOffset(i);
10314  const ImGuiID column_id = window->DC.ColumnsSetId + ImGuiID(i);
10315  const float column_w = 4.0f; // Width for interaction
10316  const ImRect column_rect(ImVec2(x - column_w, y1), ImVec2(x + column_w, y2));
10317  if (IsClippedEx(column_rect, &column_id, false))
10318  continue;
10319 
10320  bool hovered = false, held = false;
10321  if (!(window->DC.ColumnsFlags & ImGuiColumnsFlags_NoResize))
10322  {
10323  ButtonBehavior(column_rect, column_id, &hovered, &held);
10324  if (hovered || held)
10326  if (held && g.ActiveIdIsJustActivated)
10327  g.ActiveIdClickOffset.x -= column_w; // Store from center of column line (we used a 8 wide rect for columns clicking). This is used by GetDraggedColumnOffset().
10328  if (held)
10329  dragging_column = i;
10330  }
10331 
10332  // Draw column
10334  const float xi = (float)(int)x;
10335  window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);
10336  }
10337 
10338  // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
10339  if (dragging_column != -1)
10340  {
10341  float x = GetDraggedColumnOffset(dragging_column);
10342  SetColumnOffset(dragging_column, x);
10343  }
10344  }
10345 
10346  window->DC.ColumnsSetId = 0;
10347  window->DC.ColumnsCurrent = 0;
10348  window->DC.ColumnsCount = 1;
10349  window->DC.ColumnsFlags = 0;
10350  window->DC.ColumnsData.resize(0);
10351  window->DC.ColumnsOffsetX = 0.0f;
10352  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
10353 }
10354 
10355 // [2017/08: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
10356 void ImGui::Columns(int columns_count, const char* id, bool border)
10357 {
10358  ImGuiWindow* window = GetCurrentWindow();
10359  IM_ASSERT(columns_count >= 1);
10360 
10361  if (window->DC.ColumnsCount != columns_count && window->DC.ColumnsCount != 1)
10362  EndColumns();
10363 
10364  ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
10365  //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
10366  if (columns_count != 1)
10367  BeginColumns(id, columns_count, flags);
10368 }
10369 
10370 void ImGui::Indent(float indent_w)
10371 {
10372  ImGuiContext& g = *GImGui;
10373  ImGuiWindow* window = GetCurrentWindow();
10374  window->DC.IndentX += (indent_w > 0.0f) ? indent_w : g.Style.IndentSpacing;
10375  window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
10376 }
10377 
10378 void ImGui::Unindent(float indent_w)
10379 {
10380  ImGuiContext& g = *GImGui;
10381  ImGuiWindow* window = GetCurrentWindow();
10382  window->DC.IndentX -= (indent_w > 0.0f) ? indent_w : g.Style.IndentSpacing;
10383  window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
10384 }
10385 
10386 void ImGui::TreePush(const char* str_id)
10387 {
10388  ImGuiWindow* window = GetCurrentWindow();
10389  Indent();
10390  window->DC.TreeDepth++;
10391  PushID(str_id ? str_id : "#TreePush");
10392 }
10393 
10394 void ImGui::TreePush(const void* ptr_id)
10395 {
10396  ImGuiWindow* window = GetCurrentWindow();
10397  Indent();
10398  window->DC.TreeDepth++;
10399  PushID(ptr_id ? ptr_id : (const void*)"#TreePush");
10400 }
10401 
10403 {
10404  ImGuiWindow* window = GetCurrentWindow();
10405  Indent();
10406  window->DC.TreeDepth++;
10407  window->IDStack.push_back(id);
10408 }
10409 
10411 {
10412  ImGuiWindow* window = GetCurrentWindow();
10413  Unindent();
10414  window->DC.TreeDepth--;
10415  PopID();
10416 }
10417 
10418 void ImGui::Value(const char* prefix, bool b)
10419 {
10420  Text("%s: %s", prefix, (b ? "true" : "false"));
10421 }
10422 
10423 void ImGui::Value(const char* prefix, int v)
10424 {
10425  Text("%s: %d", prefix, v);
10426 }
10427 
10428 void ImGui::Value(const char* prefix, unsigned int v)
10429 {
10430  Text("%s: %d", prefix, v);
10431 }
10432 
10433 void ImGui::Value(const char* prefix, float v, const char* float_format)
10434 {
10435  if (float_format)
10436  {
10437  char fmt[64];
10438  ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format);
10439  Text(fmt, prefix, v);
10440  }
10441  else
10442  {
10443  Text("%s: %.3f", prefix, v);
10444  }
10445 }
10446 
10447 //-----------------------------------------------------------------------------
10448 // PLATFORM DEPENDENT HELPERS
10449 //-----------------------------------------------------------------------------
10450 
10451 #if defined(_WIN32) && !defined(_WINDOWS_) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS))
10452 #undef WIN32_LEAN_AND_MEAN
10453 #define WIN32_LEAN_AND_MEAN
10454 #include <windows.h>
10455 #endif
10456 
10457 // Win32 API clipboard implementation
10458 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS)
10459 
10460 #ifdef _MSC_VER
10461 #pragma comment(lib, "user32")
10462 #endif
10463 
10464 static const char* GetClipboardTextFn_DefaultImpl(void*)
10465 {
10466  static ImVector<char> buf_local;
10467  buf_local.clear();
10468  if (!OpenClipboard(NULL))
10469  return NULL;
10470  HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
10471  if (wbuf_handle == NULL)
10472  {
10473  CloseClipboard();
10474  return NULL;
10475  }
10476  if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
10477  {
10478  int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
10479  buf_local.resize(buf_len);
10480  ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);
10481  }
10482  GlobalUnlock(wbuf_handle);
10483  CloseClipboard();
10484  return buf_local.Data;
10485 }
10486 
10487 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
10488 {
10489  if (!OpenClipboard(NULL))
10490  return;
10491  const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
10492  HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
10493  if (wbuf_handle == NULL)
10494  return;
10495  ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle);
10496  ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL);
10497  GlobalUnlock(wbuf_handle);
10498  EmptyClipboard();
10499  SetClipboardData(CF_UNICODETEXT, wbuf_handle);
10500  CloseClipboard();
10501 }
10502 
10503 #else
10504 
10505 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
10506 static const char* GetClipboardTextFn_DefaultImpl(void*)
10507 {
10508  ImGuiContext& g = *GImGui;
10509  return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin();
10510 }
10511 
10512 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
10513 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
10514 {
10515  ImGuiContext& g = *GImGui;
10516  g.PrivateClipboard.clear();
10517  const char* text_end = text + strlen(text);
10518  g.PrivateClipboard.resize((int)(text_end - text) + 1);
10519  memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text));
10520  g.PrivateClipboard[(int)(text_end - text)] = 0;
10521 }
10522 
10523 #endif
10524 
10525 // Win32 API IME support (for Asian languages, etc.)
10526 #if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS)
10527 
10528 #include <imm.h>
10529 #ifdef _MSC_VER
10530 #pragma comment(lib, "imm32")
10531 #endif
10532 
10533 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
10534 {
10535  // Notify OS Input Method Editor of text input position
10536  if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle)
10537  if (HIMC himc = ImmGetContext(hwnd))
10538  {
10539  COMPOSITIONFORM cf;
10540  cf.ptCurrentPos.x = x;
10541  cf.ptCurrentPos.y = y;
10542  cf.dwStyle = CFS_FORCE_POSITION;
10543  ImmSetCompositionWindow(himc, &cf);
10544  }
10545 }
10546 
10547 #else
10548 
10549 static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
10550 
10551 #endif
10552 
10553 //-----------------------------------------------------------------------------
10554 // HELP
10555 //-----------------------------------------------------------------------------
10556 
10557 void ImGui::ShowMetricsWindow(bool* p_open)
10558 {
10559  if (ImGui::Begin("ImGui Metrics", p_open))
10560  {
10561  ImGui::Text("ImGui %s", ImGui::GetVersion());
10562  ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
10563  ImGui::Text("%d vertices, %d indices (%d triangles)", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices, ImGui::GetIO().MetricsRenderIndices / 3);
10564  ImGui::Text("%d allocations", ImGui::GetIO().MetricsAllocs);
10565  static bool show_clip_rects = true;
10566  ImGui::Checkbox("Show clipping rectangles when hovering an ImDrawCmd", &show_clip_rects);
10567  ImGui::Separator();
10568 
10569  struct Funcs
10570  {
10571  static void NodeDrawList(ImDrawList* draw_list, const char* label)
10572  {
10573  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);
10574  if (draw_list == ImGui::GetWindowDrawList())
10575  {
10576  ImGui::SameLine();
10577  ImGui::TextColored(ImColor(255,100,100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
10578  if (node_open) ImGui::TreePop();
10579  return;
10580  }
10581  if (!node_open)
10582  return;
10583 
10584  ImDrawList* overlay_draw_list = &GImGui->OverlayDrawList; // Render additional visuals into the top-most draw list
10585  overlay_draw_list->PushClipRectFullScreen();
10586  int elem_offset = 0;
10587  for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
10588  {
10589  if (pcmd->UserCallback)
10590  {
10591  ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
10592  continue;
10593  }
10594  ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
10595  bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.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);
10596  if (show_clip_rects && ImGui::IsItemHovered())
10597  {
10598  ImRect clip_rect = pcmd->ClipRect;
10599  ImRect vtxs_rect;
10600  for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
10601  vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
10602  clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255));
10603  vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255));
10604  }
10605  if (!pcmd_node_open)
10606  continue;
10607  ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
10608  while (clipper.Step())
10609  for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
10610  {
10611  char buf[300], *buf_p = buf;
10612  ImVec2 triangles_pos[3];
10613  for (int n = 0; n < 3; n++, vtx_i++)
10614  {
10615  ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i];
10616  triangles_pos[n] = v.pos;
10617  buf_p += sprintf(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);
10618  }
10619  ImGui::Selectable(buf, false);
10620  if (ImGui::IsItemHovered())
10621  overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle
10622  }
10623  ImGui::TreePop();
10624  }
10625  overlay_draw_list->PopClipRect();
10626  ImGui::TreePop();
10627  }
10628 
10629  static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
10630  {
10631  if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size))
10632  return;
10633  for (int i = 0; i < windows.Size; i++)
10634  Funcs::NodeWindow(windows[i], "Window");
10635  ImGui::TreePop();
10636  }
10637 
10638  static void NodeWindow(ImGuiWindow* window, const char* label)
10639  {
10640  if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window))
10641  return;
10642  NodeDrawList(window->DrawList, "DrawList");
10643  ImGui::BulletText("Pos: (%.1f,%.1f)", window->Pos.x, window->Pos.y);
10644  ImGui::BulletText("Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
10645  ImGui::BulletText("Scroll: (%.2f,%.2f)", window->Scroll.x, window->Scroll.y);
10646  ImGui::BulletText("Active: %d, Accessed: %d", window->Active, window->Accessed);
10647  if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
10648  if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
10649  ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));
10650  ImGui::TreePop();
10651  }
10652  };
10653 
10654  ImGuiContext& g = *GImGui; // Access private state
10655  Funcs::NodeWindows(g.Windows, "Windows");
10656  if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.RenderDrawLists[0].Size))
10657  {
10658  for (int i = 0; i < g.RenderDrawLists[0].Size; i++)
10659  Funcs::NodeDrawList(g.RenderDrawLists[0][i], "DrawList");
10660  ImGui::TreePop();
10661  }
10662  if (ImGui::TreeNode("Popups", "Open Popups Stack (%d)", g.OpenPopupStack.Size))
10663  {
10664  for (int i = 0; i < g.OpenPopupStack.Size; i++)
10665  {
10666  ImGuiWindow* window = g.OpenPopupStack[i].Window;
10667  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" : "");
10668  }
10669  ImGui::TreePop();
10670  }
10671  if (ImGui::TreeNode("Basic state"))
10672  {
10673  ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
10674  ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
10675  ImGui::Text("HoveredId: 0x%08X/0x%08X", g.HoveredId, g.HoveredIdPreviousFrame); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
10676  ImGui::Text("ActiveId: 0x%08X/0x%08X", g.ActiveId, g.ActiveIdPreviousFrame);
10677  ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
10678  ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
10679  ImGui::TreePop();
10680  }
10681  }
10682  ImGui::End();
10683 }
10684 
10685 //-----------------------------------------------------------------------------
10686 
10687 // Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
10688 // Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github.
10689 #ifdef IMGUI_INCLUDE_IMGUI_USER_INL
10690 #include "imgui_user.inl"
10691 #endif
10692 
10693 //-----------------------------------------------------------------------------
~ImGuiWindow()
Definition: imgui.cpp:1822
IMGUI_API bool BeginCombo(const char *label, const char *preview_value, ImVec2 popup_size=ImVec2(0.0f, 0.0f))
Definition: imgui.cpp:8622
ImGuiCol Col
void SetNextWindowPosCenter(ImGuiCond cond=0)
Definition: imgui.cpp:5184
void Add(const ImVec2 &rhs)
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val)
Definition: imgui.cpp:4888
IMGUI_API void SetNextWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition: imgui.cpp:5190
ImRect SetNextWindowSizeConstraintRect
IMGUI_API bool ColorPicker3(const char *label, float col[3], ImGuiColorEditFlags flags=0)
Definition: imgui.cpp:9553
ImVec2 BackupCursorPos
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))
Definition: imgui.cpp:5860
IMGUI_API bool SliderBehavior(const ImRect &frame_bb, ImGuiID id, float *v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags=0)
Definition: imgui.cpp:6629
ImGuiWindow * RootNonPopupWindow
IMGUI_API void TextColoredV(const ImVec4 &col, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:5474
const char *(* GetClipboardTextFn)(void *user_data)
Definition: imgui.h:818
ImGuiCond SetNextWindowCollapsedCond
int FocusIdxTabRequestNext
float Framerate
Definition: imgui.h:860
int FocusIdxTabCounter
IMGUI_API float GetCursorPosX()
Definition: imgui.cpp:5328
bool HasSelection() const
void PathStroke(ImU32 col, bool closed, float thickness=1.0f)
Definition: imgui.h:1280
IMGUI_API bool IsAnyWindowHovered()
Definition: imgui.cpp:3177
IMGUI_API float * GetFloatRef(ImGuiID key, float default_val=0.0f)
Definition: imgui.cpp:1440
IMGUI_API ImVec2 GetCursorStartPos()
Definition: imgui.cpp:5361
unsigned int ImU32
Definition: imgui.h:66
IMGUI_API void SetTooltip(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:3459
IMGUI_API void RenderText(ImVec2 pos, const char *text, const char *text_end=NULL, bool hide_text_after_hash=true)
Definition: imgui.cpp:2923
IMGUI_API bool IsMouseReleased(int button)
Definition: imgui.cpp:3270
bool MouseDrawCursor
Definition: imgui.h:839
IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiCond cond=0)
Definition: imgui.cpp:6315
IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2 &size, ImGuiWindowFlags extra_flags=0)
Definition: imgui.cpp:3774
ImDrawList ** CmdLists
Definition: imgui.h:1316
ImRect WindowRectClipped
IMGUI_API bool RadioButton(const char *label, bool active)
Definition: imgui.cpp:7490
#define STB_TEXTEDIT_K_LINESTART
Definition: imgui.cpp:7692
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition: imgui.cpp:5133
bool OSXBehaviors
Definition: imgui.h:805
IMGUI_API ImVec2 GetCursorPos()
Definition: imgui.cpp:5322
void(* MemFreeFn)(void *ptr)
Definition: imgui.h:825
ImGuiCond SetWindowPosAllowFlags
IMGUI_API bool BeginPopupContextItem(const char *str_id, int mouse_button=1)
Definition: imgui.cpp:3679
ImDrawIdx * _IdxWritePtr
Definition: imgui.h:1238
IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio=0.5f)
Definition: imgui.cpp:5416
ImVec2 GetCenter() const
bool ActiveIdIsJustActivated
const char * LogFilename
Definition: imgui.h:787
IMGUI_API float GetFontSize()
Definition: imgui.cpp:5302
IMGUI_API void AddCircle(const ImVec2 &centre, float radius, ImU32 col, int num_segments=12, float thickness=1.0f)
Definition: imgui_draw.cpp:902
ImVec2 GetBR() const
ImRect TitleBarRect() const
bool IsLoaded() const
Definition: imgui.h:1490
int ImTextCharFromUtf8(unsigned int *out_char, const char *in_text, const char *in_text_end)
Definition: imgui.cpp:1034
ImGuiCond SetNextTreeNodeOpenCond
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)
Definition: imgui_draw.cpp:841
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))
Definition: imgui.cpp:5888
IMGUI_API void SetVoidPtr(ImGuiID key, void *val)
Definition: imgui.cpp:1484
float ModalWindowDarkeningRatio
ImGuiWindow * ParentWindow
IMGUI_API void PushColumnClipRect(int column_index=-1)
Definition: imgui.cpp:10226
IMGUI_API void PopTextureID()
Definition: imgui_draw.cpp:272
ImVec2 ActiveIdClickOffset
IMGUI_API void ColorEditOptionsPopup(const float *col, ImGuiColorEditFlags flags)
Definition: imgui.cpp:9285
IMGUI_API void ProgressBar(float fraction, const ImVec2 &size_arg=ImVec2(-1, 0), const char *overlay=NULL)
Definition: imgui.cpp:7392
IMGUI_API float RoundScalar(float value, int decimal_precision)
Definition: imgui.cpp:6586
ImVec2 MousePos
Definition: imgui.h:836
IMGUI_API void AddInputCharacter(ImWchar c)
Definition: imgui.cpp:799
IMGUI_API void SetColumnWidth(int column_index, float width)
Definition: imgui.cpp:10217
ImVector< ImWchar > Text
IMGUI_API ImGuiStorage * GetStateStorage()
Definition: imgui.cpp:5449
IMGUI_API void PopClipRect()
Definition: imgui_draw.cpp:259
void OnKeyPressed(int key)
Definition: imgui.cpp:7709
void(* SetClipboardTextFn)(void *user_data, const char *text)
Definition: imgui.h:819
IMGUI_API void DeleteChars(int pos, int bytes_count)
Definition: imgui.cpp:7719
IMGUI_API void Clear()
Definition: imgui.cpp:1369
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)
Definition: imgui.cpp:8402
IMGUI_API const char * FindRenderedTextEnd(const char *text, const char *text_end=NULL)
Definition: imgui.cpp:2838
int WantCaptureMouseNextFrame
IMGUI_API bool IsRootWindowFocused()
Definition: imgui.cpp:5002
IMGUI_API void ChannelsSetCurrent(int channel_index)
Definition: imgui_draw.cpp:346
IMGUI_API void PopItemFlag()
Definition: imgui.cpp:4785
IMGUI_API bool IsWindowFocused()
Definition: imgui.cpp:4996
void PathFillConvex(ImU32 col)
Definition: imgui.h:1279
IMGUI_API bool InputInt3(const char *label, int v[3], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8563
IMGUI_API void SetCursorPos(const ImVec2 &local_pos)
Definition: imgui.cpp:5340
bool ImTriangleContainsPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition: imgui.cpp:847
ImGuiLayoutType LayoutType
IMGUI_API void split(char separator, ImVector< TextRange > &out)
Definition: imgui.cpp:1532
void resize(int new_size)
Definition: imgui.h:928
int ImTextStrToUtf8(char *buf, int buf_size, const ImWchar *in_text, const ImWchar *in_text_end)
Definition: imgui.cpp:1173
ImVec2 SetNextWindowContentSizeVal
float FontWindowScale
int ImStrlenW(const ImWchar *str)
Definition: imgui.cpp:910
Definition: imgui.h:96
IMGUI_API bool IsMouseClicked(int button, bool repeat=false)
Definition: imgui.cpp:3252
IMGUI_API bool IsItemClicked(int mouse_button=0)
Definition: imgui.cpp:3369
IMGUI_API bool IsKeyPressed(int user_key_index, bool repeat=true)
Definition: imgui.cpp:3222
bool SetNextWindowCollapsedVal
float CurveTessellationTol
Definition: imgui.h:769
int TooltipOverrideCount
IMGUI_API void PushMultiItemsWidths(int components, float width_full=0.0f)
Definition: imgui.cpp:4705
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding=0.0f)
Definition: imgui.cpp:3021
bool ActiveIdAllowOverlap
IMGUI_API void Initialize()
Definition: imgui.cpp:2402
IMGUI_API void PopTextWrapPos()
Definition: imgui.cpp:4819
ImVec2 ScrollbarClickDeltaToGrabCenter
ImVec2 DisplaySize
Definition: imgui.h:783
ImGuiInputTextFlags Flags
Definition: imgui.h:1064
IMGUI_API const ImFontGlyph * FindGlyph(ImWchar c) const
IMGUI_API void CalcListClipping(int items_count, float items_height, int *out_items_display_start, int *out_items_display_end)
Definition: imgui.cpp:3110
IMGUI_API bool IsMouseDown(int button)
Definition: imgui.cpp:3245
bool MouseClicked[5]
Definition: imgui.h:872
ImVector< ImFontGlyph > Glyphs
Definition: imgui.h:1468
int FramerateSecPerFrameIdx
IMGUI_API void ClearFreeMemory()
Definition: imgui_draw.cpp:141
IMGUI_API void AddInputCharactersUTF8(const char *utf8_chars)
Definition: imgui.cpp:809
ImVec2 ItemSpacing
Definition: imgui.h:755
IMGUI_API ImVec2 GetItemRectMin()
Definition: imgui.cpp:3400
IMGUI_API bool IsItemActive()
Definition: imgui.cpp:3358
IMGUI_API bool ColorPicker4(const char *label, float col[4], ImGuiColorEditFlags flags=0, const float *ref_col=NULL)
Definition: imgui.cpp:9601
IMGUI_API void * MemAlloc(size_t sz)
Definition: imgui.cpp:2081
IMGUI_API void SetHoveredID(ImGuiID id)
Definition: imgui.cpp:1887
ImGuiID HoveredId
IMGUI_API void append(const char *fmt,...) IM_FMTARGS(2)
Definition: imgui.cpp:1633
bool Valid
Definition: imgui.h:1315
ImDrawList OverlayDrawList
int FocusIdxAllRequestCurrent
IMGUI_API void SetNextWindowFocus()
Definition: imgui.cpp:5227
IMGUI_API ImVec2 GetMouseDragDelta(int button=0, float lock_threshold=-1.0f)
Definition: imgui.cpp:3318
IMGUI_API void NewFrame()
Definition: imgui.cpp:2170
IMGUI_API bool IsRootWindowOrAnyChildHovered()
Definition: imgui.cpp:5014
float CalcExtraSpace(float avail_w)
Definition: imgui.cpp:1681
bool BackupActiveIdIsAlive
void ImStrncpy(char *dst, const char *src, int count)
Definition: imgui.cpp:896
int ImGuiTreeNodeFlags
Definition: imgui.h:83
IMGUI_API void EndTooltip()
Definition: imgui.cpp:3472
IMGUI_API bool FocusableItemRegister(ImGuiWindow *window, ImGuiID id, bool tab_stop=true)
Definition: imgui.cpp:2022
IMGUI_API bool InputInt4(const char *label, int v[4], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8568
ImVector< ImGuiIniData > Settings
IMGUI_API void LogButtons()
Definition: imgui.cpp:6004
int ImGuiColorEditFlags
Definition: imgui.h:76
ImGuiID MovedWindowMoveId
bool MouseReleased[5]
Definition: imgui.h:876
float TitleBarHeight() const
IMGUI_API void CaptureMouseFromApp(bool capture=true)
Definition: imgui.cpp:3353
IMGUI_API void PushTextureID(const ImTextureID &texture_id)
Definition: imgui_draw.cpp:266
int ImGuiLayoutType
int size() const
Definition: imgui.h:1006
ImVec2 ItemInnerSpacing
Definition: imgui.h:756
int(* ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data)
Definition: imgui.h:84
float Descent
Definition: imgui.h:1479
IMGUI_API void SetScrollHere(float center_y_ratio=0.5f)
Definition: imgui.cpp:5428
float FramerateSecPerFrameAccum
float MouseClickedTime[5]
Definition: imgui.h:874
IMGUI_API void PopAllowKeyboardFocus()
Definition: imgui.cpp:4797
IMGUI_API bool SmallButton(const char *label)
Definition: imgui.cpp:5804
ImVector< ImGuiItemFlags > ItemFlagsStack
IMGUI_API bool IsMouseHoveringRect(const ImVec2 &r_min, const ImVec2 &r_max, bool clip=true)
Definition: imgui.cpp:3162
#define IM_F32_TO_INT8_SAT(_VAL)
Definition: imgui.cpp:824
IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, bool intersect_with_current_clip_rect)
Definition: imgui.cpp:2690
IMGUI_API bool BeginChild(const char *str_id, const ImVec2 &size=ImVec2(0, 0), bool border=false, ImGuiWindowFlags extra_flags=0)
Definition: imgui.cpp:3736
IMGUI_API void PathArcToFast(const ImVec2 &centre, float radius, int a_min_of_12, int a_max_of_12)
Definition: imgui_draw.cpp:683
IMGUI_API void ShowMetricsWindow(bool *p_open=NULL)
Definition: imgui.cpp:10557
IMGUI_API bool Draw(const char *label="Filter (inc,-exc)", float width=0.0f)
Definition: imgui.cpp:1520
ImGuiID MoveId
int CmdListsCount
Definition: imgui.h:1317
IMGUI_API void BeginTooltip()
Definition: imgui.cpp:3467
IMGUI_API bool TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:6217
ImVec2 SetNextWindowSizeVal
IMGUI_API bool IsWindowAppearing()
Definition: imgui.cpp:5144
IMGUI_API bool IsWindowRectHovered()
Definition: imgui.cpp:4990
float KeysDownDuration[512]
Definition: imgui.h:881
ImVec2 DisplayVisibleMax
Definition: imgui.h:802
#define STB_TEXTEDIT_K_UNDO
Definition: imgui.cpp:7698
void swap(ImVector< T > &rhs)
Definition: imgui.h:924
ImGuiContext * GImGui
Definition: imgui.cpp:661
IMGUI_API bool * GetBoolRef(ImGuiID key, bool default_val=false)
Definition: imgui.cpp:1435
IMGUI_API void Indent(float indent_w=0.0f)
Definition: imgui.cpp:10370
const ImFontGlyph * FallbackGlyph
Definition: imgui.h:1471
#define STB_TEXTEDIT_K_TEXTEND
Definition: imgui.cpp:7695
ImGuiColumnsFlags ColumnsFlags
IMGUI_API void AddTriangleFilled(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, ImU32 col)
Definition: imgui_draw.cpp:891
float BackupCurrentLineTextBaseOffset
#define IM_OFFSETOF(_TYPE, _ELM)
IMGUI_API void PushTextWrapPos(float wrap_pos_x=0.0f)
Definition: imgui.cpp:4812
ImVec2 SetWindowPosVal
IMGUI_API void PushButtonRepeat(bool repeat)
Definition: imgui.cpp:4802
ImVec2 SetNextWindowPosVal
ImGuiStorage StateStorage
ImVec2 MouseClickedPos[5]
Definition: imgui.h:873
IMGUI_API void ResetMouseDragDelta(int button=0)
Definition: imgui.cpp:3330
IMGUI_API bool IsWindowHovered()
Definition: imgui.cpp:4984
ImVector< ImDrawList * > RenderDrawLists[3]
bool MouseDoubleClicked[5]
Definition: imgui.h:875
IMGUI_API void BulletTextV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:6391
ImGuiItemFlags ItemFlags
ImVec2 DisplayVisibleMin
Definition: imgui.h:801
int ImStricmp(const char *str1, const char *str2)
Definition: imgui.cpp:882
char * ImStrdup(const char *str)
Definition: imgui.cpp:903
int MetricsAllocs
Definition: imgui.h:861
bool SetNextWindowFocus
ImGuiPlotType
IMGUI_API ImGuiMouseCursor GetMouseCursor()
Definition: imgui.cpp:3338
IMGUI_API float GetColumnOffset(int column_index=-1)
Definition: imgui.cpp:10162
const char * begin() const
Definition: imgui.h:975
int ImTextCountUtf8BytesFromStr(const ImWchar *in_text, const ImWchar *in_text_end)
Definition: imgui.cpp:1189
#define STB_TEXTEDIT_K_SHIFT
Definition: imgui.cpp:7702
ImVec2 ImTriangleClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
Definition: imgui.cpp:866
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char *label, const char *label_end=NULL)
Definition: imgui.cpp:6075
void *(* MemAllocFn)(size_t sz)
Definition: imgui.h:824
IMGUI_API void SetStateStorage(ImGuiStorage *tree)
Definition: imgui.cpp:5443
IMGUI_API void AddLine(const ImVec2 &a, const ImVec2 &b, ImU32 col, float thickness=1.0f)
Definition: imgui_draw.cpp:807
IMGUI_API void AddPolyline(const ImVec2 *points, const int num_points, ImU32 col, bool closed, float thickness, bool anti_aliased)
Definition: imgui_draw.cpp:419
IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect=false)
Definition: imgui_draw.cpp:235
float FrameRounding
Definition: imgui.h:754
int ImGuiItemFlags
bool WantCaptureKeyboard
Definition: imgui.h:857
IMGUI_API bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:8396
void * GetVarPtr(ImGuiStyle *style) const
Definition: imgui.cpp:4863
IMGUI_API bool TreeNodeV(const char *str_id, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:6248
bool empty() const
Definition: imgui.h:908
ImVector< ImFont * > Fonts
Definition: imgui.h:1454
IMGUI_API ImVec2 GetItemRectSize()
Definition: imgui.cpp:3412
IMGUI_API float GetWindowWidth()
Definition: imgui.cpp:5020
IMGUI_API void ** GetVoidPtrRef(ImGuiID key, void *default_val=NULL)
Definition: imgui.cpp:1448
ImGuiColorEditFlags ColorEditOptions
IMGUI_API void Build()
Definition: imgui.cpp:1550
IMGUI_API void ClosePopup(ImGuiID id)
Definition: imgui.cpp:3554
IMGUI_API bool TreeNode(const char *label)
Definition: imgui.cpp:6294
IMGUI_API ImVec2 GetContentRegionMax()
Definition: imgui.cpp:5234
#define STB_TEXTEDIT_K_REDO
Definition: imgui.cpp:7699
ImVector< ImGuiWindow * > CurrentWindowStack
T * Data
Definition: imgui.h:899
ImVector< Pair > Data
Definition: imgui.h:1032
int KeyMap[ImGuiKey_COUNT]
Definition: imgui.h:791
IMGUI_API bool CheckboxFlags(const char *label, unsigned int *flags, unsigned int flags_value)
Definition: imgui.cpp:7475
iterator begin()
Definition: imgui.h:916
ImVector< ImFont * > FontStack
ImVec2 uv
Definition: imgui.h:1201
void(* ImeSetInputScreenPosFn)(int x, int y)
Definition: imgui.h:829
IMGUI_API bool ColorEdit4(const char *label, float col[4], ImGuiColorEditFlags flags=0)
Definition: imgui.cpp:9374
IMGUI_API void SetWindowPos(const ImVec2 &pos, ImGuiCond cond=0)
Definition: imgui.cpp:5062
IMGUI_API bool DragBehavior(const ImRect &frame_bb, ImGuiID id, float *v, float v_speed, float v_min, float v_max, int decimal_precision, float power)
Definition: imgui.cpp:6961
IMGUI_API bool BeginMenuBar()
Definition: imgui.cpp:8992
IMGUI_API ImGuiTextFilter(const char *default_filter="")
Definition: imgui.cpp:1506
IMGUI_API void AlignFirstTextHeightToWidgets()
Definition: imgui.cpp:5627
bool empty() const
Definition: imgui.h:977
float ColumnsMinSpacing
Definition: imgui.h:759
float DeltaTime
Definition: imgui.h:784
#define STB_TEXTEDIT_K_DOWN
Definition: imgui.cpp:7691
bool WantCaptureMouse
Definition: imgui.h:856
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))
Definition: imgui.cpp:7380
IMGUI_API void MemFree(void *ptr)
Definition: imgui.cpp:2087
IMGUI_API ImGuiContext * CreateContext(void *(*malloc_fn)(size_t)=NULL, void(*free_fn)(void *)=NULL)
Definition: imgui.cpp:2125
IMGUI_API void Clear()
Definition: imgui_draw.cpp:125
IMGUI_API void TextWrappedV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:5504
unsigned short ImDrawIdx
Definition: imgui.h:1193
#define STB_TEXTEDIT_K_LINEEND
Definition: imgui.cpp:7693
#define STB_TEXTEDIT_GETWIDTH_NEWLINE
IMGUI_API bool IsMousePosValid(const ImVec2 *mouse_pos=NULL)
Definition: imgui.cpp:3310
IMGUI_API ImVec2 GetMousePos()
Definition: imgui.cpp:3295
IMGUI_API void Bullet()
Definition: imgui.cpp:6368
IMGUI_API void BeginColumns(const char *id, int count, ImGuiColumnsFlags flags=0)
Definition: imgui.cpp:10235
ImDrawList * DrawList
ImVec2 SetWindowPosPivot
ImGuiDrawContext DC
ImRect Rect() const
ImGuiTextBuffer * LogClipboard
IMGUI_API bool InputFloat3(const char *label, float v[3], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8520
unsigned short ImWchar
Definition: imgui.h:71
int ImGuiCond
Definition: imgui.h:79
IMGUI_API bool PassFilter(const char *text, const char *text_end=NULL) const
Definition: imgui.cpp:1567
ImGuiDataType Type
Definition: imgui.cpp:4861
IMGUI_API bool IsClippedEx(const ImRect &bb, const ImGuiID *id, bool clip_even_when_logged)
Definition: imgui.cpp:2011
IMGUI_API bool BeginPopup(const char *str_id)
Definition: imgui.cpp:3610
int ImGuiInputTextFlags
Definition: imgui.h:81
ImGuiID GetIDNoKeepAlive(const char *str, const char *str_end=NULL)
Definition: imgui.cpp:1847
ImGuiID ActiveId
ImGuiMouseCursorData MouseCursorData[ImGuiMouseCursor_Count_]
IMGUI_API void SameLine(float pos_x=0.0f, float spacing_w=-1.0f)
Definition: imgui.cpp:10051
ImDrawData RenderDrawData
void pop_back()
Definition: imgui.h:942
IMGUI_API void SetMouseCursor(ImGuiMouseCursor type)
Definition: imgui.cpp:3343
IMGUI_API bool SliderFloat2(const char *label, float v[2], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6904
IMGUI_API ImVec2 GetContentRegionAvail()
Definition: imgui.cpp:5243
int Size
Definition: imgui.h:897
ImRect MenuBarRect() const
ImGuiCond SetNextWindowSizeCond
ImGuiSimpleColumns MenuColumns
IMGUI_API void CaptureKeyboardFromApp(bool capture=true)
Definition: imgui.cpp:3348
IMGUI_API void RenderRectFilledRangeH(ImDrawList *draw_list, const ImRect &rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding)
bool SetNextTreeNodeOpenVal
float CurrentLineTextBaseOffset
IMGUI_API void SetFloat(ImGuiID key, float val)
Definition: imgui.cpp:1473
ImGuiInputTextFlags EventFlag
Definition: imgui.h:1063
float DragSpeedDefaultRatio
ImVec2 DisplayOffset
Definition: imgui.h:1467
IMGUI_API float GetScrollMaxY()
Definition: imgui.cpp:5396
IMGUI_API void SetCurrentContext(ImGuiContext *ctx)
Definition: imgui.cpp:2116
ImFontAtlas * ContainerAtlas
Definition: imgui.h:1478
IMGUI_API ImDrawList * GetWindowDrawList()
Definition: imgui.cpp:5291
IMGUI_API bool ItemAdd(const ImRect &bb, const ImGuiID *id)
Definition: imgui.cpp:1949
ImVector< ImGuiWindow * > Windows
IMGUI_API bool Begin(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:3988
#define IM_ASSERT(_EXPR)
Definition: imgui.h:30
IMGUI_API bool InputInt2(const char *label, int v[2], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8558
int WantTextInputNextFrame
int ImGuiWindowFlags
Definition: imgui.h:78
IMGUI_API bool IsKeyDown(int user_key_index)
Definition: imgui.cpp:3196
IMGUI_API void PopStyleVar(int count=1)
Definition: imgui.cpp:4916
IMGUI_API void SetScrollY(float scroll_y)
Definition: imgui.cpp:5409
float FontSize
Definition: imgui.h:1465
ImVec2 SizeContentsExplicit
float Alpha
Definition: imgui.h:747
IMGUI_API void SetTooltipV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:3452
ImGuiID GetID(const char *str, const char *str_end=NULL)
Definition: imgui.cpp:1831
IMGUI_API ImVec2 CalcTextSize(const char *text, const char *text_end=NULL, bool hide_text_after_double_hash=false, float wrap_width=-1.0f)
Definition: imgui.cpp:3081
IMGUI_API bool CollapsingHeader(const char *label, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:6185
#define IM_COL32_A_SHIFT
Definition: imgui.h:1109
ImGuiStb::STB_TexteditState StbState
IMGUI_API ImVec2 GetWindowContentRegionMin()
Definition: imgui.cpp:5255
IMGUI_API void AddTriangle(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, ImU32 col, float thickness=1.0f)
Definition: imgui_draw.cpp:880
IMGUI_API bool BeginPopupContextWindow(const char *str_id=NULL, int mouse_button=1, bool also_over_items=true)
Definition: imgui.cpp:3686
IMGUI_API bool ListBoxHeader(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:8838
IMGUI_API void Dummy(const ImVec2 &size)
Definition: imgui.cpp:9959
IMGUI_API void KeepAliveID(ImGuiID id)
Definition: imgui.cpp:1894
void Expand(const float amount)
IMGUI_API void BulletText(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:6415
IMGUI_API bool IsAnyItemHovered()
Definition: imgui.cpp:3374
ImVector< char > TempTextBuffer
int ImTextStrFromUtf8(ImWchar *buf, int buf_size, const char *in_text, const char *in_text_end, const char **in_text_remaining)
Definition: imgui.cpp:1092
const char * ImStristr(const char *haystack, const char *haystack_end, const char *needle, const char *needle_end)
Definition: imgui.cpp:924
char front() const
Definition: imgui.h:978
float w
Definition: imgui.h:108
ImFont InputTextPasswordFont
IMGUI_API const char * GetStyleColorName(ImGuiCol idx)
Definition: imgui.cpp:4931
IMGUI_API bool IsMouseDragging(int button=0, float lock_threshold=-1.0f)
Definition: imgui.cpp:3284
void * ImFileLoadToMemory(const char *filename, const char *file_open_mode, int *out_file_size, int padding_bytes)
Definition: imgui.cpp:1324
int DisplayStart
Definition: imgui.h:1155
IMGUI_API ImVec2 GetWindowContentRegionMax()
Definition: imgui.cpp:5261
IMGUI_API bool IsRectVisible(const ImVec2 &size)
Definition: imgui.cpp:9970
IMGUI_API bool SliderIntN(const char *label, int *v, int components, int v_min, int v_max, const char *display_format)
Definition: imgui.cpp:6919
IMGUI_API bool Step()
Definition: imgui.cpp:1732
ImVec2 WindowMinSize
Definition: imgui.h:749
ImGuiTextEditState InputTextState
IMGUI_API void ColorTooltip(const char *text, const float *col, ImGuiColorEditFlags flags)
Definition: imgui.cpp:9145
IMGUI_API void TextUnformatted(const char *text, const char *text_end=NULL)
Definition: imgui.cpp:5520
IMGUI_API void TreePushRawID(ImGuiID id)
Definition: imgui.cpp:10402
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 *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:7137
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled)
Definition: imgui.cpp:4775
ImGuiWindow * RootWindow
ImU32 ImHash(const void *data, int data_size, ImU32 seed)
Definition: imgui.cpp:985
float MouseDownDuration[5]
Definition: imgui.h:878
ImVector< ImGuiColMod > ColorModifiers
ImGuiWindow * MovedWindow
IMGUI_API void SetColumnOffset(int column_index, float offset_x)
Definition: imgui.cpp:10184
IMGUI_API void SetNextWindowContentWidth(float width)
Definition: imgui.cpp:5213
ImVec2 Max
IMGUI_API void Unindent(float indent_w=0.0f)
Definition: imgui.cpp:10378
const char * _OwnerName
Definition: imgui.h:1235
IMGUI_API int GetColumnsCount()
Definition: imgui.cpp:10129
void ClipWith(const ImRect &clip)
IMGUI_API bool InputIntN(const char *label, int *v, int components, ImGuiInputTextFlags extra_flags)
Definition: imgui.cpp:8530
#define IM_COL32(R, G, B, A)
Definition: imgui.h:1112
#define IM_COL32_B_SHIFT
Definition: imgui.h:1108
const float * Values
Definition: imgui.cpp:7356
IMGUI_API bool SliderAngle(const char *label, float *v_rad, float v_degrees_min=-360.0f, float v_degrees_max=+360.0f)
Definition: imgui.cpp:6848
float ItemWidthDefault
IMGUI_API void FocusWindow(ImGuiWindow *window)
Definition: imgui.cpp:4666
ImVector< ImDrawCmd > CmdBuffer
Definition: imgui.h:1230
IMGUI_API bool ColorEdit3(const char *label, float col[3], ImGuiColorEditFlags flags=0)
Definition: imgui.cpp:9280
ImGuiWindow * ActiveIdWindow
bool AutoFitOnlyGrows
ImVector< ImGuiStyleMod > StyleModifiers
IMGUI_API void AddText(const ImVec2 &pos, ImU32 col, const char *text_begin, const char *text_end=NULL)
Definition: imgui_draw.cpp:962
bool Contains(const ImVec2 &p) const
void * ClipboardUserData
Definition: imgui.h:820
ImRect ContentsRegionRect
int ImGuiStyleVar
Definition: imgui.h:74
ImGuiID HoveredIdPreviousFrame
IMGUI_API bool SliderFloat3(const char *label, float v[3], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6909
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup()
Definition: imgui.cpp:3301
float MouseDoubleClickTime
Definition: imgui.h:788
void(* ImGuiSizeConstraintCallback)(ImGuiSizeConstraintCallbackData *data)
Definition: imgui.h:85
float GrabMinSize
Definition: imgui.h:762
float KeysDownDurationPrev[512]
Definition: imgui.h:882
IMGUI_API ImGuiIO & GetIO()
Definition: imgui.cpp:2144
void ImTriangleBarycentricCoords(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p, float &out_u, float &out_v, float &out_w)
Definition: imgui.cpp:855
IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect &aabb, const char *label, ImGuiDataType data_type, void *data_ptr, ImGuiID id, int decimal_precision)
Definition: imgui.cpp:6532
int MetricsRenderIndices
Definition: imgui.h:863
int ImGuiKey
Definition: imgui.h:75
float GetWidth() const
ImVec2 OsImePosSet
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 *display_format="%.0f")
Definition: imgui.cpp:7215
IMGUI_API bool InputFloat2(const char *label, float v[2], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8515
IMGUI_API void LabelTextV(const char *label, const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:5640
IMGUI_API bool IsRootWindowOrAnyChildFocused()
Definition: imgui.cpp:5008
float z
Definition: imgui.h:108
IMGUI_API bool InputFloat4(const char *label, float v[4], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8525
ImVec2 WindowPadding
IMGUI_API bool IsItemRectHovered()
Definition: imgui.cpp:1984
IMGUI_API ImFont * GetFont()
Definition: imgui.cpp:5297
IMGUI_API void EndGroup()
Definition: imgui.cpp:10006
IMGUI_API float GetTime()
Definition: imgui.cpp:2160
bool KeysDown[512]
Definition: imgui.h:844
IMGUI_API int GetColumnIndex()
Definition: imgui.cpp:10123
#define IM_COL32_A_MASK
Definition: imgui.h:1110
#define IM_F32_TO_INT8_UNBOUND(_VAL)
Definition: imgui.cpp:823
IMGUI_API void ChannelsMerge()
Definition: imgui_draw.cpp:312
IMGUI_API bool IsKeyReleased(int user_key_index)
Definition: imgui.cpp:3235
IMGUI_API void Spacing()
Definition: imgui.cpp:9951
IMGUI_API void LogToFile(int max_depth=-1, const char *filename=NULL)
Definition: imgui.cpp:5939
ImGuiID ActiveIdPreviousFrame
IMGUI_API void VerticalSeparator()
Definition: imgui.cpp:9932
IMGUI_API void SetNextWindowSizeConstraints(const ImVec2 &size_min, const ImVec2 &size_max, ImGuiSizeConstraintCallback custom_callback=NULL, void *custom_callback_data=NULL)
Definition: imgui.cpp:5197
IMGUI_API bool InputFloat(const char *label, float *v, float step=0.0f, float step_fast=0.0f, int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8470
IMGUI_API ImGuiContext * GetCurrentContext()
Definition: imgui.cpp:2111
#define IM_COL32_BLACK
Definition: imgui.h:1114
ImGuiCond SetNextWindowContentSizeCond
void reserve(int new_capacity)
Definition: imgui.h:930
IMGUI_API void SetWindowFocus()
Definition: imgui.cpp:5157
IMGUI_API void EndCombo()
Definition: imgui.cpp:8698
float ScrollbarRounding
Definition: imgui.h:761
float GetHeight() const
IMGUI_API bool IsWindowCollapsed()
Definition: imgui.cpp:5138
IMGUI_API void SetCursorPosX(float x)
Definition: imgui.cpp:5347
IMGUI_API float GetContentRegionAvailWidth()
Definition: imgui.cpp:5249
IMGUI_API int GetInt(ImGuiID key, int default_val=0) const
Definition: imgui.cpp:1397
#define IMGUI_VERSION
Definition: imgui.h:20
unsigned int ImGuiID
Definition: imgui.h:70
bool KeyShift
Definition: imgui.h:841
int ImTextCountCharsFromUtf8(const char *in_text, const char *in_text_end)
Definition: imgui.cpp:1111
float CalcFontSize() const
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)
Definition: imgui_draw.cpp:967
IMGUI_API void PushItemWidth(float item_width)
Definition: imgui.cpp:4698
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:5798
ImVec2 ScrollTargetCenterRatio
IMGUI_API void Value(const char *prefix, bool b)
Definition: imgui.cpp:10418
ImU32 col
Definition: imgui.h:1202
IMGUI_API float GetItemsLineHeightWithSpacing()
Definition: imgui.cpp:5285
ImGuiWindow * HoveredRootWindow
int FocusIdxTabRequestCurrent
IMGUI_API ImGuiWindow * GetParentWindow()
Definition: imgui.cpp:1865
IMGUI_API void Separator()
Definition: imgui.cpp:9885
IMGUI_API void End()
Definition: imgui.cpp:4537
#define STB_TEXTEDIT_K_DELETE
Definition: imgui.cpp:7696
void clear()
Definition: imgui.h:915
IMGUI_API void FocusableItemUnregister(ImGuiWindow *window)
Definition: imgui.cpp:2046
IMGUI_API void ItemSize(const ImVec2 &size, float text_offset_y=0.0f)
Definition: imgui.cpp:1915
Definition: imgui.h:106
IMGUI_API void BeginGroup()
Definition: imgui.cpp:9983
bool FontAllowUserScaling
Definition: imgui.h:798
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 *display_format="%.3f", const char *display_format_max=NULL, float power=1.0f)
Definition: imgui.cpp:7142
ImVec4 BackupValue
IMGUI_API bool SliderFloat4(const char *label, float v[4], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6914
ImGuiDir
IMGUI_API void AddCircleFilled(const ImVec2 &centre, float radius, ImU32 col, int num_segments=12)
Definition: imgui_draw.cpp:912
const ImWchar * ImStrbolW(const ImWchar *buf_mid_line, const ImWchar *buf_begin)
Definition: imgui.cpp:917
ImVector< ImGuiColumnData > ColumnsData
float DragSpeedScaleSlow
IMGUI_API float GetScrollX()
Definition: imgui.cpp:5380
IMGUI_API void Begin(int items_count, float items_height=-1.0f)
Definition: imgui.cpp:1705
ImTextureID TexID
Definition: imgui.h:1443
int ImGuiSliderFlags
IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale=1.0f)
Definition: imgui.cpp:3032
ImVec2 GetTL() const
float GetCharAdvance(ImWchar c) const
Definition: imgui.h:1489
ImGuiID ScalarAsInputTextId
bool MouseDown[5]
Definition: imgui.h:837
IMGUI_API bool SliderInt4(const char *label, int v[4], int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6956
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 *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:7041
#define va_copy(dest, src)
Definition: imgui.cpp:1608
IMGUI_API bool BeginPopupContextVoid(const char *str_id=NULL, int mouse_button=1)
Definition: imgui.cpp:3696
unsigned int _VtxCurrentIdx
Definition: imgui.h:1236
int ImGuiMouseCursor
Definition: imgui.h:77
IMGUI_API float GetColumnWidth(int column_index=-1)
Definition: imgui.cpp:10208
IMGUI_API ImVec2 GetWindowSize()
Definition: imgui.cpp:5074
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)
Definition: imgui.cpp:9180
float PrevLineTextBaseOffset
void Update(int count, float spacing, bool clear)
Definition: imgui.cpp:1653
IMGUI_API void EndPopup()
Definition: imgui.cpp:3661
IMGUI_API void appendv(const char *fmt, va_list args) IM_FMTLIST(2)
Definition: imgui.cpp:1612
ImVec2 ImLineClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &p)
Definition: imgui.cpp:833
IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col)
Definition: imgui.cpp:3065
IMGUI_API float GetTreeNodeToLabelSpacing()
Definition: imgui.cpp:6309
bool KeyCtrl
Definition: imgui.h:840
IMGUI_API ImVec2 GetFontTexUvWhitePixel()
Definition: imgui.cpp:5307
bool AntiAliasedShapes
Definition: imgui.h:768
#define STB_TEXTEDIT_K_BACKSPACE
Definition: imgui.cpp:7697
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char *text, const char *text_end, float wrap_width)
Definition: imgui.cpp:2950
IMGUI_API void TextV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:5455
IMGUI_API void RenderBullet(ImVec2 pos)
Definition: imgui.cpp:3059
IMGUI_API void NextColumn()
Definition: imgui.cpp:10090
IMGUI_API bool ColorButton(const char *desc_id, const ImVec4 &col, ImGuiColorEditFlags flags=0, ImVec2 size=ImVec2(0, 0))
Definition: imgui.cpp:9232
float x
Definition: imgui.h:108
ImVector< ImGuiPopupRef > OpenPopupStack
bool MouseDownOwned[5]
Definition: imgui.h:877
float DeclColumns(float w0, float w1, float w2)
Definition: imgui.cpp:1670
float IndentSpacing
Definition: imgui.h:758
IMGUI_API float GetWindowHeight()
Definition: imgui.cpp:5026
IMGUI_API bool ButtonEx(const char *label, const ImVec2 &size_arg=ImVec2(0, 0), ImGuiButtonFlags flags=0)
Definition: imgui.cpp:5761
ImVector< char > PrivateClipboard
#define STB_TEXTEDIT_K_WORDLEFT
Definition: imgui.cpp:7700
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 *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:7127
ImGuiPlotArrayGetterData(const float *values, int stride)
Definition: imgui.cpp:7359
IMGUI_API bool BeginMainMenuBar()
Definition: imgui.cpp:8967
IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4 &in)
Definition: imgui.cpp:1213
ImVec2 DisplaySafeAreaPadding
Definition: imgui.h:766
ImGuiCond SetWindowCollapsedAllowFlags
IMGUI_API bool SliderFloatN(const char *label, float *v, int components, float v_min, float v_max, const char *display_format, float power)
Definition: imgui.cpp:6877
float BackupGroupOffsetX
IMGUI_API void PushFont(ImFont *font)
Definition: imgui.cpp:4757
float SettingsDirtyTimer
ImGuiWindow * CurrentWindow
IMGUI_API void SetNextWindowPos(const ImVec2 &pos, ImGuiCond cond=0, const ImVec2 &pivot=ImVec2(0, 0))
Definition: imgui.cpp:5175
ImVec2 DisplayWindowPadding
Definition: imgui.h:765
IMGUI_API void SetClipboardText(const char *text)
Definition: imgui.cpp:2098
float IniSavingRate
Definition: imgui.h:785
IMGUI_API bool InvisibleButton(const char *str_id, const ImVec2 &size)
Definition: imgui.cpp:5816
float y
Definition: imgui.h:98
ImGuiWindow(const char *name)
Definition: imgui.cpp:1773
IMGUI_API void SetBool(ImGuiID key, bool val)
Definition: imgui.cpp:1468
ImGuiStyle Style
int MetricsRenderVertices
Definition: imgui.h:862
IMGUI_API void EndChild()
Definition: imgui.cpp:3747
IMGUI_API float GetWindowContentRegionWidth()
Definition: imgui.cpp:5267
IMGUI_API float GetScrollMaxX()
Definition: imgui.cpp:5390
ImGuiSizeConstraintCallback SetNextWindowSizeConstraintCallback
ImVec2 FramePadding
Definition: imgui.h:753
IMGUI_API bool BeginMenu(const char *label, bool enabled=true)
Definition: imgui.cpp:9029
IMGUI_API float GetTextLineHeightWithSpacing()
Definition: imgui.cpp:5279
IMGUI_API void TextWrapped(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:5512
ImGuiCond SetNextWindowPosCond
iterator insert(const_iterator it, const value_type &v)
Definition: imgui.h:945
int LogAutoExpandMaxDepth
bool SetNextWindowSizeConstraint
IMGUI_API void ListBoxFooter()
Definition: imgui.cpp:8879
IMGUI_API void TextColored(const ImVec4 &col, const char *fmt,...) IM_FMTARGS(2)
Definition: imgui.cpp:5481
float FramerateSecPerFrame[120]
ImVec4 Colors[ImGuiCol_COUNT]
Definition: imgui.h:770
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border=true, float rounding=0.0f)
Definition: imgui.cpp:3009
ImGuiWindowFlags Flags
ImVec2 GetTR() const
void PrimVtx(const ImVec2 &pos, const ImVec2 &uv, ImU32 col)
Definition: imgui.h:1307
IMGUI_API float CalcItemWidth()
Definition: imgui.cpp:4726
IMGUI_API void SetInt(ImGuiID key, int val)
Definition: imgui.cpp:1457
ImDrawCallback UserCallback
Definition: imgui.h:1185
int TotalIdxCount
Definition: imgui.h:1319
IMGUI_API int GetKeyPressedAmount(int key_index, float repeat_delay, float rate)
Definition: imgui.cpp:3213
IMGUI_API void Text(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:5466
IMGUI_API void DestroyContext(ImGuiContext *ctx)
Definition: imgui.cpp:2135
IMGUI_API void LogToTTY(int max_depth=-1)
Definition: imgui.cpp:5924
float MouseDoubleClickMaxDist
Definition: imgui.h:789
#define IM_COL32_G_SHIFT
Definition: imgui.h:1107
float GrabRounding
Definition: imgui.h:763
ImDrawVert * _VtxWritePtr
Definition: imgui.h:1237
float FontGlobalScale
Definition: imgui.h:797
IMGUI_API ImVec2 GetCursorScreenPos()
Definition: imgui.cpp:5367
IMGUI_API ImGuiWindow * FindWindowByName(const char *name)
Definition: imgui.cpp:3834
ImVec2 SetNextWindowPosPivot
IMGUI_API bool DragIntN(const char *label, int *v, int components, float v_speed, int v_min, int v_max, const char *display_format)
Definition: imgui.cpp:7178
int ImFormatStringV(char *buf, int buf_size, const char *fmt, va_list args)
Definition: imgui.cpp:973
bool KeySuper
Definition: imgui.h:843
IMGUI_API void Shutdown()
Definition: imgui.cpp:2414
#define STB_TEXTEDIT_K_WORDRIGHT
Definition: imgui.cpp:7701
void(* RenderDrawListsFn)(ImDrawData *data)
Definition: imgui.h:814
IMGUI_API void EndChildFrame()
Definition: imgui.cpp:3784
int FocusIdxAllCounter
IMGUI_API bool SliderInt3(const char *label, int v[3], int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6951
IMGUI_API ImGuiStyle()
Definition: imgui.cpp:668
ImVec4 ColorPickerRef
IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6856
void push_back(const value_type &v)
Definition: imgui.h:941
#define IM_PI
ImVector< ImGuiWindow * > WindowsSortBuffer
IMGUI_API void PopItemWidth()
Definition: imgui.cpp:4719
ImVec2 GetBL() const
float KeyRepeatDelay
Definition: imgui.h:792
#define STB_TEXTEDIT_K_RIGHT
Definition: imgui.cpp:7689
IMGUI_API void TreePop()
Definition: imgui.cpp:10410
iterator erase(const_iterator it)
Definition: imgui.h:944
float MouseDragThreshold
Definition: imgui.h:790
int TotalVtxCount
Definition: imgui.h:1318
IMGUI_API bool DragFloatN(const char *label, float *v, int components, float v_speed, float v_min, float v_max, const char *display_format, float power)
Definition: imgui.cpp:7100
value_type * iterator
Definition: imgui.h:902
#define IM_NEWLINE
Definition: imgui.cpp:830
IMGUI_API void PathArcTo(const ImVec2 &centre, float radius, float a_min, float a_max, int num_segments=10)
Definition: imgui_draw.cpp:712
ImVec2 MousePosPrev
Definition: imgui.h:871
ImVec2 TexUvWhitePixel
Definition: imgui.h:1453
IMGUI_API void EndColumns()
Definition: imgui.cpp:10291
int FocusIdxAllRequestNext
bool AntiAliasedLines
Definition: imgui.h:767
IMGUI_API bool InputScalarEx(const char *label, ImGuiDataType data_type, void *data_ptr, void *step_ptr, void *step_fast_ptr, const char *scalar_format, ImGuiInputTextFlags extra_flags)
Definition: imgui.cpp:8414
ImVec2 ScrollbarSizes
IMGUI_API void LogText(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:2850
IMGUI_API bool IsItemVisible()
Definition: imgui.cpp:3384
IMGUI_API int * GetIntRef(ImGuiID key, int default_val=0)
Definition: imgui.cpp:1427
IMGUI_API bool ButtonBehavior(const ImRect &bb, ImGuiID id, bool *out_hovered, bool *out_held, ImGuiButtonFlags flags=0)
Definition: imgui.cpp:5673
int AutoFitChildAxises
#define STB_TEXTEDIT_STRING
ImVector< float > TextWrapPosStack
Definition: imgui.h:1462
ImWchar InputCharacters[16+1]
Definition: imgui.h:845
IMGUI_API void EndFrame()
Definition: imgui.cpp:2705
IMGUI_API int CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
Definition: imgui.cpp:3203
IMGUI_API float GetTextLineHeight()
Definition: imgui.cpp:5273
IMGUI_API bool ItemHoverable(const ImRect &bb, ImGuiID id)
Definition: imgui.cpp:1991
IMGUI_API bool SliderInt2(const char *label, int v[2], int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6946
float DragSpeedScaleFast
IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col)
Definition: imgui.cpp:4827
IMGUI_API void LabelText(const char *label, const char *fmt,...) IM_FMTARGS(2)
Definition: imgui.cpp:5665
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)
Definition: imgui.cpp:7245
int ImFormatString(char *buf, int buf_size, const char *fmt,...)
Definition: imgui.cpp:960
IMGUI_API void TreePush(const char *str_id=NULL)
Definition: imgui.cpp:10386
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow *window)
Definition: imgui.cpp:1872
IMGUI_API bool MenuItem(const char *label, const char *shortcut=NULL, bool selected=false, bool enabled=true)
Definition: imgui.cpp:8929
ImGuiWindow * NavWindow
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2 &pos, float radius)
Definition: imgui.cpp:5836
IMGUI_API bool GetBool(ImGuiID key, bool default_val=false) const
Definition: imgui.cpp:1405
void PathLineTo(const ImVec2 &pos)
Definition: imgui.h:1277
IMGUI_API int GetFrameCount()
Definition: imgui.cpp:2165
IMGUI_API void End()
Definition: imgui.cpp:1721
#define STB_TEXTEDIT_K_UP
Definition: imgui.cpp:7690
bool HoveredIdAllowOverlap
void * ImeWindowHandle
Definition: imgui.h:830
float BackupFloat[2]
IMGUI_API bool BeginPopupModal(const char *name, bool *p_open=NULL, ImGuiWindowFlags extra_flags=0)
Definition: imgui.cpp:3633
int WantCaptureKeyboardNextFrame
IMGUI_API const char * GetClipboardText()
Definition: imgui.cpp:2093
IMGUI_API bool Selectable(const char *label, bool selected=false, ImGuiSelectableFlags flags=0, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:8748
ImGuiID PopupId
IMGUI_API void SetNextWindowContentSize(const ImVec2 &size)
Definition: imgui.cpp:5206
IMGUI_API ImGuiIO()
Definition: imgui.cpp:747
ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const
Definition: imgui.h:777
IMGUI_API int GetKeyIndex(ImGuiKey imgui_key)
Definition: imgui.cpp:3189
IMGUI_API void PopButtonRepeat()
Definition: imgui.cpp:4807
bool WantTextInput
Definition: imgui.h:858
IMGUI_API bool Checkbox(const char *label, bool *v)
Definition: imgui.cpp:7427
IMGUI_API float GetFloat(ImGuiID key, float default_val=0.0f) const
Definition: imgui.cpp:1410
ImVector< ImDrawVert > VtxBuffer
Definition: imgui.h:1232
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:6028
float Ascent
Definition: imgui.h:1479
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond=0)
Definition: imgui.cpp:5220
ImVec2 WindowTitleAlign
Definition: imgui.h:751
#define IM_COL32_R_SHIFT
Definition: imgui.h:1106
IMGUI_API bool VSliderInt(const char *label, const ImVec2 &size, int *v, int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6866
IMGUI_API float CalcWrapWidthForPos(const ImVec2 &pos, float wrap_pos_x)
Definition: imgui.cpp:2065
ImVec2 MouseDelta
Definition: imgui.h:865
IMGUI_API ImVec2 GetItemRectMax()
Definition: imgui.cpp:3406
unsigned int ElemCount
Definition: imgui.h:1182
float MouseDragMaxDistanceSqr[5]
Definition: imgui.h:880
IMGUI_API void * GetVoidPtr(ImGuiID key) const
Definition: imgui.cpp:1418
IMGUI_API float GetScrollY()
Definition: imgui.cpp:5385
IMGUI_API void SetCursorScreenPos(const ImVec2 &pos)
Definition: imgui.cpp:5373
IMGUI_API bool InputFloatN(const char *label, float *v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags)
Definition: imgui.cpp:8487
int MetricsActiveWindows
Definition: imgui.h:864
int ImGuiSelectableFlags
Definition: imgui.h:82
IMGUI_API void LogToClipboard(int max_depth=-1)
Definition: imgui.cpp:5966
float MenuBarHeight() const
float FallbackAdvanceX
Definition: imgui.h:1472
#define STB_TEXTEDIT_K_TEXTSTART
Definition: imgui.cpp:7694
const char * begin() const
Definition: imgui.h:1004
IMGUI_API void EndMenuBar()
Definition: imgui.cpp:9012
#define IM_COL32_BLACK_TRANS
Definition: imgui.h:1115
void clear()
Definition: imgui.h:1008
ImVec2 ButtonTextAlign
Definition: imgui.h:764
IMGUI_API const char * GetVersion()
Definition: imgui.cpp:2104
float MouseWheel
Definition: imgui.h:838
int ImStrnicmp(const char *str1, const char *str2, int count)
Definition: imgui.cpp:889
ImVector< ImGuiGroupData > GroupStack
IMGUI_API void PushID(const char *str_id)
Definition: imgui.cpp:6322
IMGUI_API void Clear()
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 *display_format="%.0f", const char *display_format_max=NULL)
Definition: imgui.cpp:7220
IMGUI_API ImGuiID GetID(const char *str_id)
Definition: imgui.cpp:6353
bool KeyAlt
Definition: imgui.h:842
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)
Definition: imgui.cpp:7812
IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus)
Definition: imgui.cpp:4792
unsigned long long ImU64
Definition: imgui.h:89
ImVector< ImGuiID > IDStack
ImGuiMouseCursor MouseCursor
ImVector< float > IndexAdvanceX
Definition: imgui.h:1469
int ImGuiColumnsFlags
Definition: imgui.h:80
float KeyRepeatRate
Definition: imgui.h:793
IMGUI_API bool ListBox(const char *label, int *current_item, const char *const *items, int items_count, int height_in_items=-1)
Definition: imgui.cpp:8895
ImVec2 pos
Definition: imgui.h:1200
ImVec2 TouchExtraPadding
Definition: imgui.h:757
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)
Definition: imgui.cpp:2969
ImGuiWindow * GetCurrentWindow()
IMGUI_API void SetAllInt(int val)
Definition: imgui.cpp:1495
IMGUI_API ImVec2 GetWindowPos()
Definition: imgui.cpp:5032
void Floor()
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 *display_format="%.0f")
Definition: imgui.cpp:7205
IMGUI_API ImGuiStyle & GetStyle()
Definition: imgui.cpp:2149
IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float &out_h, float &out_s, float &out_v)
Definition: imgui.cpp:1257
int ImGuiCol
Definition: imgui.h:73
IMGUI_API bool Combo(const char *label, int *current_item, const char *const *items, int items_count, int height_in_items=-1)
Definition: imgui.cpp:8602
IMGUI_API void SetItemAllowOverlap()
Definition: imgui.cpp:3391
IMGUI_API void CloseCurrentPopup()
Definition: imgui.cpp:3563
IMGUI_API void PushClipRectFullScreen()
Definition: imgui_draw.cpp:253
IMGUI_API void PopClipRect()
Definition: imgui.cpp:2697
IMGUI_API bool TreeNodeExV(const char *str_id, ImGuiTreeNodeFlags flags, const char *fmt, va_list args) IM_FMTLIST(3)
Definition: imgui.cpp:6226
const char * IniFilename
Definition: imgui.h:786
float MouseDownDurationPrev[5]
Definition: imgui.h:879
IMGUI_API void OpenPopup(const char *str_id)
Definition: imgui.cpp:3497
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
void * SetNextWindowSizeConstraintCallbackUserData
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 *display_format="%.0f")
Definition: imgui.cpp:7210
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y)
Definition: imgui.cpp:2052
ImGuiDataType
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 *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:7132
IMGUI_API bool SliderFloat(const char *label, float *v, float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6747
ImVector< char > InitialText
FILE * ImFileOpen(const char *filename, const char *mode)
Definition: imgui.cpp:1306
iterator end()
Definition: imgui.h:918
IMGUI_API void SetCursorPosY(float y)
Definition: imgui.cpp:5354
IMGUI_API void AddRectFilled(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners_flags=~0)
Definition: imgui_draw.cpp:825
IMGUI_API void AddRect(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners_flags=~0, float thickness=1.0f)
Definition: imgui_draw.cpp:817
ImVec2 DragLastMouseDelta
ImGuiWindow * Window
ImVec2 BackupCursorMaxPos
ImVec2 SizeContents
const char * end() const
Definition: imgui.h:976
float Scale
Definition: imgui.h:1466
ImVector< ImDrawIdx > IdxBuffer
Definition: imgui.h:1231
IMGUI_API void TextDisabled(const char *fmt,...) IM_FMTARGS(1)
Definition: imgui.cpp:5496
int AutoPosLastDirection
IMGUI_API ImDrawData * GetDrawData()
Definition: imgui.cpp:2155
IMGUI_API void OpenPopupEx(ImGuiID id, bool reopen_existing)
Definition: imgui.cpp:3482
IMGUI_API void ClearActiveID()
Definition: imgui.cpp:1882
IMGUI_API const ImVec4 & GetStyleColorVec4(ImGuiCol idx)
Definition: imgui.cpp:1239
IMGUI_API void Columns(int count=1, const char *id=NULL, bool border=true)
Definition: imgui.cpp:10356
ImGuiStorage * StateStorage
IMGUI_API void SetWindowFontScale(float scale)
Definition: imgui.cpp:5312
ImVec2 Min
#define IM_ARRAYSIZE(_ARR)
Definition: imgui_demo.cpp:66
IMGUI_API void InsertChars(int pos, const char *text, const char *text_end=NULL)
Definition: imgui.cpp:7737
IMGUI_API bool DragInt(const char *label, int *v, float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: imgui.cpp:7168
IMGUI_API bool IsMouseDoubleClicked(int button)
Definition: imgui.cpp:3277
ImFontAtlas * Fonts
Definition: imgui.h:796
ImFont * FontDefault
Definition: imgui.h:799
ImVec2 FontTexUvWhitePixel
IMGUI_API void StyleColorsClassic(ImGuiStyle *dst=NULL)
Definition: imgui.cpp:697
ImGuiWindow * HoveredWindow
IMGUI_API bool IsAnyItemActive()
Definition: imgui.cpp:3379
float ChildWindowRounding
Definition: imgui.h:752
ImVec2 WindowPadding
Definition: imgui.h:748
IMGUI_API void EndMenu()
Definition: imgui.cpp:9139
bool Overlaps(const ImRect &r) const
float BackupCurrentLineHeight
IMGUI_API void PrimReserve(int idx_count, int vtx_count)
Definition: imgui_draw.cpp:359
IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float &out_r, float &out_g, float &out_b)
Definition: imgui.cpp:1279
IMGUI_API void PopID()
Definition: imgui.cpp:6347
float WindowRounding
Definition: imgui.h:750
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))
Definition: imgui.cpp:7369
IMGUI_API void ChannelsSplit(int channels_count)
Definition: imgui_draw.cpp:279
IMGUI_API float GetCursorPosY()
Definition: imgui.cpp:5334
IMGUI_API void SetColorEditOptions(ImGuiColorEditFlags flags)
Definition: imgui.cpp:9214
IMGUI_API bool IsItemHovered()
Definition: imgui.cpp:1968
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
Definition: imgui.cpp:3582
IMGUI_API void SetKeyboardFocusHere(int offset=0)
Definition: imgui.cpp:5436
ImVec2 GetSize() const
float ScrollbarSize
Definition: imgui.h:760
int ImGuiButtonFlags
void * ImTextureID
Definition: imgui.h:72
IMGUI_API void LogFinish()
Definition: imgui.cpp:5980
IMGUI_API int ParseFormatPrecision(const char *fmt, int default_value)
Definition: imgui.cpp:6558
float AdvanceX
Definition: imgui.h:1353
ImGuiStyleVar VarIdx
ImGuiWindow * GetCurrentWindowRead()
IMGUI_API void SetScrollX(float scroll_x)
Definition: imgui.cpp:5402
ImVector< ImGuiPopupRef > CurrentPopupStack
IMGUI_API void PopFont()
Definition: imgui.cpp:4767
ImVec2 ScrollTarget
float y
Definition: imgui.h:108
ImVector< float > ItemWidthStack
IMGUI_API void Render()
Definition: imgui.cpp:2769
IMGUI_API void TreeAdvanceToLabelPos()
Definition: imgui.cpp:6302
#define STB_TEXTEDIT_K_LEFT
Definition: imgui.cpp:7688
float x
Definition: imgui.h:98
IMGUI_API bool InputInt(const char *label, int *v, int step=1, int step_fast=100, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8480
ImGuiCond SetWindowSizeAllowFlags
ImVec2 OsImePosRequest
IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in)
Definition: imgui.cpp:1203
#define IM_COL32_WHITE
Definition: imgui.h:1113
IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul=1.0f)
Definition: imgui.cpp:1223
IMGUI_API void PopStyleColor(int count=1)
Definition: imgui.cpp:4847
ImVector< ImGuiWindow * > ChildWindows
char TempBuffer[1024 *3+1]
ImVector< unsigned short > IndexLookup
Definition: imgui.h:1470
ImVector< ImVec4 > _ClipRectStack
Definition: imgui.h:1239
IMGUI_API void EndMainMenuBar()
Definition: imgui.cpp:8985
float DragCurrentValue
value_type & back()
Definition: imgui.h:922
IMGUI_API bool VSliderFloat(const char *label, const ImVec2 &size, float *v, float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6805
IMGUI_API void TextDisabledV(const char *fmt, va_list args) IM_FMTLIST(1)
Definition: imgui.cpp:5489
IMGUI_API void NewLine()
Definition: imgui.cpp:10074
IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2 &pos, bool on_edge=false, float outward=+0.0f)
Definition: imgui.cpp:3418
IMGUI_API bool IsPopupOpen(const char *str_id)
Definition: imgui.cpp:3627
IMGUI_API void SetWindowSize(const ImVec2 &size, ImGuiCond cond=0)
Definition: imgui.cpp:5110