imgui.cpp
Go to the documentation of this file.
1 // dear imgui, v1.49
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 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 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
9 // This library is free but I need your support to sustain development and maintenance.
10 // If you work for a company, please consider financial support, e.g: https://www.patreon.com/imgui
11 
12 /*
13 
14  Index
15  - MISSION STATEMENT
16  - END-USER GUIDE
17  - PROGRAMMER GUIDE (read me!)
18  - API BREAKING CHANGES (read me when you update!)
19  - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
20  - How can I help?
21  - How do I update to a newer version of ImGui?
22  - What is ImTextureID and how do I display an image?
23  - I integrated ImGui in my engine and the text or lines are blurry..
24  - I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around..
25  - How can I have multiple widgets with the same label? Can I have widget without a label? (Yes). A primer on the purpose of labels/IDs.
26  - How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application?
27  - How can I load a different font than the default?
28  - How can I load multiple fonts?
29  - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
30  - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
31  - ISSUES & TODO-LIST
32  - CODE
33 
34 
35  MISSION STATEMENT
36  =================
37 
38  - easy to use to create code-driven and data-driven tools
39  - easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools
40  - easy to hack and improve
41  - minimize screen real-estate usage
42  - minimize setup and maintenance
43  - minimize state storage on user side
44  - portable, minimize dependencies, run on target (consoles, phones, etc.)
45  - efficient runtime (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)
46  - read about immediate-mode gui principles @ http://mollyrocket.com/861, http://mollyrocket.com/forums/index.html
47 
48  Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
49  - doesn't look fancy, doesn't animate
50  - limited layout features, intricate layouts are typically crafted in code
51  - occasionally uses statically sized buffers for string manipulations - won't crash, but some very long pieces of text may be clipped. functions like ImGui::TextUnformatted() don't have such restriction.
52 
53 
54  END-USER GUIDE
55  ==============
56 
57  - double-click title bar to collapse window
58  - click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin()
59  - click and drag on lower right corner to resize window
60  - click and drag on any empty space to move window
61  - double-click/double-tap on lower right corner grip to auto-fit to content
62  - TAB/SHIFT+TAB to cycle through keyboard editable fields
63  - use mouse wheel to scroll
64  - use CTRL+mouse wheel to zoom window contents (if IO.FontAllowScaling is true)
65  - CTRL+Click on a slider or drag box to input value as text
66  - text editor:
67  - Hold SHIFT or use mouse to select text.
68  - CTRL+Left/Right to word jump
69  - CTRL+Shift+Left/Right to select words
70  - CTRL+A our Double-Click to select all
71  - CTRL+X,CTRL+C,CTRL+V to use OS clipboard
72  - CTRL+Z,CTRL+Y to undo/redo
73  - ESCAPE to revert text to its original value
74  - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
75 
76 
77  PROGRAMMER GUIDE
78  ================
79 
80  - read the FAQ below this section!
81  - 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.
82  - call and read ImGui::ShowTestWindow() for demo code demonstrating most features.
83  - see examples/ folder for standalone sample applications. Prefer reading examples/opengl_example/ first as it is the simplest.
84  you may be able to grab and copy a ready made imgui_impl_*** file from the examples/.
85  - customization: PushStyleColor()/PushStyleVar() or the style editor to tweak the look of the interface (e.g. if you want a more compact UI or a different color scheme).
86 
87  - getting started:
88  - init: call ImGui::GetIO() to retrieve the ImGuiIO structure and fill the fields marked 'Settings'.
89  - init: call io.Fonts->GetTexDataAsRGBA32(...) and load the font texture pixels into graphics memory.
90  - every frame:
91  1/ in your mainloop or right after you got your keyboard/mouse info, call ImGui::GetIO() and fill the fields marked 'Input'
92  2/ call ImGui::NewFrame() as early as you can!
93  3/ use any ImGui function you want between NewFrame() and Render()
94  4/ call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your RenderDrawListFn handler that you set in the IO structure.
95  (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.)
96  - all rendering information are stored into command-lists until ImGui::Render() is called.
97  - ImGui never touches or know about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide.
98  - 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.
99  - refer to the examples applications in the examples/ folder for instruction on how to setup your code.
100  - a typical application skeleton may be:
101 
102  // Application init
103  ImGuiIO& io = ImGui::GetIO();
104  io.DisplaySize.x = 1920.0f;
105  io.DisplaySize.y = 1280.0f;
106  io.IniFilename = "imgui.ini";
107  io.RenderDrawListsFn = my_render_function; // Setup a render function, or set to NULL and call GetDrawData() after Render() to access the render data.
108  // TODO: Fill others settings of the io structure
109 
110  // Load texture atlas
111  // There is a default font so you don't need to care about choosing a font yet
112  unsigned char* pixels;
113  int width, height;
114  io.Fonts->GetTexDataAsRGBA32(pixels, &width, &height);
115  // TODO: At this points you've got a texture pointed to by 'pixels' and you need to upload that your your graphic system
116  // TODO: Store your texture pointer/identifier (whatever your engine uses) in 'io.Fonts->TexID'
117 
118  // Application main loop
119  while (true)
120  {
121  // 1) get low-level inputs (e.g. on Win32, GetKeyboardState(), or poll your events, etc.)
122  // TODO: fill all fields of IO structure and call NewFrame
123  ImGuiIO& io = ImGui::GetIO();
124  io.DeltaTime = 1.0f/60.0f;
125  io.MousePos = mouse_pos;
126  io.MouseDown[0] = mouse_button_0;
127  io.MouseDown[1] = mouse_button_1;
128  io.KeysDown[i] = ...
129 
130  // 2) call NewFrame(), after this point you can use ImGui::* functions anytime
131  ImGui::NewFrame();
132 
133  // 3) most of your application code here
134  ImGui::Begin("My window");
135  ImGui::Text("Hello, world.");
136  ImGui::End();
137  MyGameUpdate(); // may use ImGui functions
138  MyGameRender(); // may use ImGui functions
139 
140  // 4) render & swap video buffers
141  ImGui::Render();
142  SwapBuffers();
143  }
144 
145  - You can read back 'io.WantCaptureMouse', 'io.WantCaptureKeybord' etc. flags from the IO structure to tell how ImGui intends to use your
146  inputs and to know if you should share them or hide them from the rest of your application. Read the FAQ below for more information.
147 
148 
149  API BREAKING CHANGES
150  ====================
151 
152  Occasionally introducing changes that are breaking the API. The breakage are generally minor and easy to fix.
153  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.
154  Also read releases logs https://github.com/ocornut/imgui/releases for more details.
155 
156  - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
157  If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
158  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.
159  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.
160  ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col)
161  {
162  float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a;
163  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);
164  }
165  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.
166  - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
167  - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
168  - 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).
169  - 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.
170  - 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).
171  - 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)
172  - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
173  - 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.
174  - 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.
175  - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
176  - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
177  - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
178  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.
179  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!
180  - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
181  - 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.
182  - 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
183  - 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.
184  you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
185  - 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.
186  this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
187  - 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.
188  - the signature of the io.RenderDrawListsFn handler has changed!
189  ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
190  became:
191  ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
192  argument 'cmd_lists' -> 'draw_data->CmdLists'
193  argument 'cmd_lists_count' -> 'draw_data->CmdListsCount'
194  ImDrawList 'commands' -> 'CmdBuffer'
195  ImDrawList 'vtx_buffer' -> 'VtxBuffer'
196  ImDrawList n/a -> 'IdxBuffer' (new)
197  ImDrawCmd 'vtx_count' -> 'ElemCount'
198  ImDrawCmd 'clip_rect' -> 'ClipRect'
199  ImDrawCmd 'user_callback' -> 'UserCallback'
200  ImDrawCmd 'texture_id' -> 'TextureId'
201  - 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.
202  - 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!
203  - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
204  - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
205  - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
206  - 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.
207  - 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
208  - 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!
209  - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
210  - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
211  - 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.
212  - 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.
213  - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
214  - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function (will obsolete).
215  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
216  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
217  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
218  - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function (will obsolete).
219  - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
220  - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function (will obsolete).
221  - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
222  - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function (will obsolete).
223  - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
224  - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
225  - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
226  - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
227  - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
228  - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
229  - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
230  (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
231  this sequence:
232  const void* png_data;
233  unsigned int png_size;
234  ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size);
235  // <Copy to GPU>
236  became:
237  unsigned char* pixels;
238  int width, height;
239  io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
240  // <Copy to GPU>
241  io.Fonts->TexID = (your_texture_identifier);
242  you now have much more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
243  it is now recommended that you sample the font texture with bilinear interpolation.
244  (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
245  (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
246  (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
247  - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
248  - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
249  - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
250  - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
251  - 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)
252  - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
253  - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
254  - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
255  - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
256  - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
257  - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
258 
259 
260  FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
261  ======================================
262 
263  Q: How can I help?
264  A: - If you are experienced enough with ImGui and with C/C++, look at the todo list and see how you want/can help!
265  - Become a Patron/donate. Convince your company to become a Patron or provide serious funding for development time.
266 
267  Q: How do I update to a newer version of ImGui?
268  A: Overwrite the following files:
269  imgui.cpp
270  imgui.h
271  imgui_demo.cpp
272  imgui_draw.cpp
273  imgui_internal.h
274  stb_rect_pack.h
275  stb_textedit.h
276  stb_truetype.h
277  Don't overwrite imconfig.h if you have made modification to your copy.
278  Check the "API BREAKING CHANGES" sections for a list of occasional API breaking changes. If you have a problem with a function, search for its name
279  in the code, there will likely be a comment about it. Please report any issue to the GitHub page!
280 
281 
282  Q: What is ImTextureID and how do I display an image?
283  A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function.
284  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!
285  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.
286  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.
287  Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing.
288  (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!)
289  To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions.
290  ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use.
291  It is your responsibility to get textures uploaded to your GPU.
292 
293  Q: I integrated ImGui in my engine and the text or lines are blurry..
294  A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
295  Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
296 
297  Q: I integrated ImGui in my engine and some elements are clipping or disappearing when I move windows around..
298  A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1,y1,x2,y2) and NOT as (x1,y1,width,height).
299 
300  Q: Can I have multiple widgets with the same label? Can I have widget without a label? (Yes)
301  A: Yes. A primer on the use of labels/IDs in ImGui..
302 
303  - Elements that are not clickable, such as Text() items don't need an ID.
304 
305  - Interactive widgets require state to be carried over multiple frames (most typically ImGui often needs to remember what is the "active" widget).
306  to do so they need an unique ID. unique ID are typically derived from a string label, an integer index or a pointer.
307 
308  Button("OK"); // Label = "OK", ID = hash of "OK"
309  Button("Cancel"); // Label = "Cancel", ID = hash of "Cancel"
310 
311  - 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
312  or in two different locations of a tree.
313 
314  - If you have a same ID twice in the same location, you'll have a conflict:
315 
316  Button("OK");
317  Button("OK"); // ID collision! Both buttons will be treated as the same.
318 
319  Fear not! this is easy to solve and there are many ways to solve it!
320 
321  - When passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases.
322  use "##" to pass a complement to the ID that won't be visible to the end-user:
323 
324  Button("Play"); // Label = "Play", ID = hash of "Play"
325  Button("Play##foo1"); // Label = "Play", ID = hash of "Play##foo1" (different from above)
326  Button("Play##foo2"); // Label = "Play", ID = hash of "Play##foo2" (different from above)
327 
328  - If you want to completely hide the label, but still need an ID:
329 
330  Checkbox("##On", &b); // Label = "", ID = hash of "##On" (no label!)
331 
332  - Occasionally/rarely you might want change a label while preserving a constant ID. This allows you to animate labels.
333  For example you may want to include varying information in a window title bar (and windows are uniquely identified by their ID.. obviously)
334  Use "###" to pass a label that isn't part of ID:
335 
336  Button("Hello###ID"; // Label = "Hello", ID = hash of "ID"
337  Button("World###ID"; // Label = "World", ID = hash of "ID" (same as above)
338 
339  sprintf(buf, "My game (%f FPS)###MyGame");
340  Begin(buf); // Variable label, ID = hash of "MyGame"
341 
342  - Use PushID() / PopID() to create scopes and avoid ID conflicts within the same Window.
343  This is the most convenient way of distinguishing ID if you are iterating and creating many UI elements.
344  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!
345 
346  for (int i = 0; i < 100; i++)
347  {
348  PushID(i);
349  Button("Click"); // Label = "Click", ID = hash of integer + "label" (unique)
350  PopID();
351  }
352 
353  for (int i = 0; i < 100; i++)
354  {
355  MyObject* obj = Objects[i];
356  PushID(obj);
357  Button("Click"); // Label = "Click", ID = hash of pointer + "label" (unique)
358  PopID();
359  }
360 
361  for (int i = 0; i < 100; i++)
362  {
363  MyObject* obj = Objects[i];
364  PushID(obj->Name);
365  Button("Click"); // Label = "Click", ID = hash of string + "label" (unique)
366  PopID();
367  }
368 
369  - More example showing that you can stack multiple prefixes into the ID stack:
370 
371  Button("Click"); // Label = "Click", ID = hash of "Click"
372  PushID("node");
373  Button("Click"); // Label = "Click", ID = hash of "node" + "Click"
374  PushID(my_ptr);
375  Button("Click"); // Label = "Click", ID = hash of "node" + ptr + "Click"
376  PopID();
377  PopID();
378 
379  - Tree nodes implicitly creates a scope for you by calling PushID().
380 
381  Button("Click"); // Label = "Click", ID = hash of "Click"
382  if (TreeNode("node"))
383  {
384  Button("Click"); // Label = "Click", ID = hash of "node" + "Click"
385  TreePop();
386  }
387 
388  - When working with trees, ID are used to preserve the open/close state of each tree node.
389  Depending on your use cases you may want to use strings, indices or pointers as ID.
390  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.
391  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!
392 
393  Q: How can I tell when ImGui wants my mouse/keyboard inputs and when I can pass them to my application?
394  A: You can read the 'io.WantCaptureXXX' flags in the ImGuiIO structure. Preferably read them after calling ImGui::NewFrame() to avoid those flags lagging by one frame.
395  When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application.
396  When 'io.WantInputsCharacters' is set to may want to notify your OS to popup an on-screen keyboard, if available.
397  ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, so 'io.WantCaptureMouse' is a more accurate and complete than testing for ImGui::IsMouseHoveringAnyWindow().
398 
399  Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13)
400  A: Use the font atlas to load the TTF file you want:
401 
402  ImGuiIO& io = ImGui::GetIO();
403  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
404  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
405 
406  Q: How can I load multiple fonts?
407  A: Use the font atlas to pack them into a single texture:
408  (Read extra_fonts/README.txt and the code in ImFontAtlas for more details.)
409 
410  ImGuiIO& io = ImGui::GetIO();
411  ImFont* font0 = io.Fonts->AddFontDefault();
412  ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
413  ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
414  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
415  // the first loaded font gets used by default
416  // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
417 
418  // Options
419  ImFontConfig config;
420  config.OversampleH = 3;
421  config.OversampleV = 1;
422  config.GlyphExtraSpacing.x = 1.0f;
423  io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config);
424 
425  // Combine multiple fonts into one
426  ImWchar ranges[] = { 0xf000, 0xf3ff, 0 };
427  ImFontConfig config;
428  config.MergeMode = true;
429  io.Fonts->AddFontDefault();
430  io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges);
431  io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese());
432 
433  Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
434  A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
435  All your strings needs to use UTF-8 encoding. 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.
436  In C++11 you can encode a string literal in UTF-8 by using the u8"hello" syntax. Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
437  You can also try to remap your local codepage characters to their Unicode codepoint using font->AddRemapChar(), but international users may have problems reading/editing your source code.
438 
439  io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese()); // Load Japanese characters
440  io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
441  io.ImeWindowHandle = MY_HWND; // To input using Microsoft IME, give ImGui the hwnd of your application
442 
443  As for text input, depends on you passing the right character code to io.AddInputCharacter(). The example applications do that.
444 
445  Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
446  A: The easiest way is to create a dummy window. Call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flag, zero background alpha,
447  then retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
448 
449  - 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.
450  - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug"
451  - 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)
452  - tip: you can call Render() multiple times (e.g for VR renders).
453  - tip: call and read the ShowTestWindow() code in imgui_demo.cpp for more example of how to use ImGui!
454 
455 
456  ISSUES & TODO-LIST
457  ==================
458  Issue numbers (#) refer to github issues listed at https://github.com/ocornut/imgui/issues
459  The list below consist mostly of notes of things to do before they are requested/discussed by users (at that point it usually happens on the github)
460 
461  - doc: add a proper documentation+regression testing system (#435)
462  - window: add a way for very transient windows (non-saved, temporary overlay over hundreds of objects) to "clean" up from the global window list. perhaps a lightweight explicit cleanup pass.
463  - window: calling SetNextWindowSize() every frame with <= 0 doesn't do anything, may be useful to allow (particularly when used for a single axis).
464  - window: auto-fit feedback loop when user relies on any dynamic layout (window width multiplier, column) appears weird to end-user. clarify.
465  - window: allow resizing of child windows (possibly given min/max for each axis?)
466  - window: background options for child windows, border option (disable rounding)
467  - window: add a way to clear an existing window instead of appending (e.g. for tooltip override using a consistent api rather than the deferred tooltip)
468  - window: resizing from any sides? + mouse cursor directives for app.
469 !- window: begin with *p_open == false should return false.
470  - window: get size/pos helpers given names (see discussion in #249)
471  - window: a collapsed window can be stuck behind the main menu bar?
472  - window: when window is small, prioritize resize button over close button.
473  - window: detect extra End() call that pop the "Debug" window out and assert at call site instead of later.
474  - window/tooltip: allow to set the width of a tooltip to allow TextWrapped() etc. while keeping the height automatic.
475  - window: increase minimum size of a window with menus or fix the menu rendering so that it doesn't look odd.
476  - draw-list: maintaining bounding box per command would allow to merge draw command when clipping isn't relied on (typical non-scrolling window or non-overflowing column would merge with previous command).
477 !- scrolling: allow immediately effective change of scroll if we haven't appended items yet
478  - splitter/separator: formalize the splitter idiom into an official api (we want to handle n-way split) (#319)
479  - widgets: display mode: widget-label, label-widget (aligned on column or using fixed size), label-newline-tab-widget etc.
480  - widgets: clean up widgets internal toward exposing everything.
481  - widgets: add disabled and read-only modes (#211)
482  - main: considering adding an Init() function? some constructs are awkward in the implementation because of the lack of them.
483 !- main: make it so that a frame with no window registered won't refocus every window on subsequent frames (~bump LastFrameActive of all windows).
484  - main: IsItemHovered() make it more consistent for various type of widgets, widgets with multiple components, etc. also effectively IsHovered() region sometimes differs from hot region, e.g tree nodes
485  - main: IsItemHovered() info stored in a stack? so that 'if TreeNode() { Text; TreePop; } if IsHovered' return the hover state of the TreeNode?
486  - input text: clean up the mess caused by converting UTF-8 <> wchar. the code is rather inefficient right now.
487  - input text: reorganize event handling, allow CharFilter to modify buffers, allow multiple events? (#541)
488  - input text: flag to disable live update of the user buffer (also applies to float/int text input)
489  - input text: resize behavior - field could stretch when being edited? hover tooltip shows more text?
490  - input text: add ImGuiInputTextFlags_EnterToApply? (off #218)
491  - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc).
492  - input text multi-line: way to dynamically grow the buffer without forcing the user to initially allocate for worse case (follow up on #200)
493  - input text multi-line: line numbers? status bar? (follow up on #200)
494  - input text: allow centering/positioning text so that ctrl+clicking Drag or Slider keeps the textual value at the same pixel position.
495  - input number: optional range min/max for Input*() functions
496  - input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled)
497  - input number: use mouse wheel to step up/down
498  - input number: applying arithmetics ops (+,-,*,/) messes up with text edit undo stack.
499  - button: provide a button that looks framed.
500  - text: proper alignment options
501  - image/image button: misalignment on padded/bordered button?
502  - image/image button: parameters are confusing, image() has tint_col,border_col whereas imagebutton() has bg_col/tint_col. Even thou they are different parameters ordering could be more consistent. can we fix that?
503  - layout: horizontal layout helper (#97)
504  - layout: horizontal flow until no space left (#404)
505  - layout: more generic alignment state (left/right/centered) for single items?
506  - layout: clean up the InputFloatN/SliderFloatN/ColorEdit4 layout code. item width should include frame padding.
507  - layout: BeginGroup() needs a border option.
508  - columns: declare column set (each column: fixed size, %, fill, distribute default size among fills) (#513, #125)
509  - columns: add a conditional parameter to SetColumnOffset() (#513, #125)
510  - columns: separator function or parameter that works within the column (currently Separator() bypass all columns) (#125)
511  - columns: columns header to act as button (~sort op) and allow resize/reorder (#513, #125)
512  - columns: user specify columns size (#513, #125)
513  - columns: flag to add horizontal separator above/below?
514  - columns/layout: setup minimum line height (equivalent of automatically calling AlignFirstTextHeightToWidgets)
515  - combo: sparse combo boxes (via function call?) / iterators
516  - combo: contents should extends to fit label if combo widget is small
517  - combo/listbox: keyboard control. need InputText-like non-active focus + key handling. considering keyboard for custom listbox (pr #203)
518  - listbox: multiple selection
519  - listbox: user may want to initial scroll to focus on the one selected value?
520  - listbox: keyboard navigation.
521  - listbox: scrolling should track modified selection.
522 !- popups/menus: clarify usage of popups id, how MenuItem/Selectable closing parent popups affects the ID, etc. this is quite fishy needs improvement! (#331, #402)
523  - popups: add variant using global identifier similar to Begin/End (#402)
524  - popups: border options. richer api like BeginChild() perhaps? (#197)
525  - tooltip: tooltip that doesn't fit in entire screen seems to lose their "last prefered button" and may teleport when moving mouse
526  - menus: local shortcuts, global shortcuts (#456, #126)
527  - menus: icons
528  - menus: menubars: some sort of priority / effect of main menu-bar on desktop size?
529  - menus: calling BeginMenu() twice with a same name doesn't seem to append nicely
530  - statusbar: add a per-window status bar helper similar to what menubar does.
531  - tabs (#261, #351)
532  - separator: separator on the initial position of a window is not visible (cursorpos.y <= clippos.y)
533 !- color: the color helpers/typing is a mess and needs sorting out.
534  - color: add a better color picker (#346)
535  - node/graph editor (#306)
536  - pie menus patterns (#434)
537  - drag'n drop, dragging helpers (carry dragging info, visualize drag source before clicking, drop target, etc.) (#143, #479)
538  - plot: PlotLines() should use the polygon-stroke facilities (currently issues with averaging normals)
539  - plot: make it easier for user to draw extra stuff into the graph (e.g: draw basis, highlight certain points, 2d plots, multiple plots)
540  - plot: "smooth" automatic scale over time, user give an input 0.0(full user scale) 1.0(full derived from value)
541  - plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID)
542  - slider: allow using the [-]/[+] buttons used by InputFloat()/InputInt()
543  - slider: initial absolute click is imprecise. change to relative movement slider (same as scrollbar).
544  - slider: add dragging-based widgets to edit values with mouse (on 2 axises), saving screen real-estate.
545  - slider: tint background based on value (e.g. v_min -> v_max, or use 0.0f either side of the sign)
546  - slider & drag: int data passing through a float
547  - drag float: up/down axis
548  - drag float: added leeway on edge (e.g. a few invisible steps past the clamp limits)
549  - tree node / optimization: avoid formatting when clipped.
550  - tree node: tree-node/header right-most side doesn't take account of horizontal scrolling.
551  - tree node: add treenode/treepush int variants? not there because (void*) cast from int warns on some platforms/settings?
552  - tree node: try to apply scrolling at time of TreePop() if node was just opened and end of node is past scrolling limits?
553  - tree node / selectable render mismatch which is visible if you use them both next to each other (e.g. cf. property viewer)
554  - tree node: tweak color scheme to distinguish headers from selected tree node (#581)
555  - textwrapped: figure out better way to use TextWrapped() in an always auto-resize context (tooltip, etc.) (#249)
556  - settings: write more decent code to allow saving/loading new fields
557  - settings: api for per-tool simple persistent data (bool,int,float,columns sizes,etc.) in .ini file
558  - style: add window shadows.
559  - style/optimization: store rounded corners in texture to use 1 quad per corner (filled and wireframe) to lower the cost of rounding.
560  - style: color-box not always square?
561  - style: a concept of "compact style" that the end-user can easily rely on (e.g. PushStyleCompact()?) that maps to other settings? avoid implementing duplicate helpers such as SmallCheckbox(), etc.
562  - style: try to make PushStyleVar() more robust to incorrect parameters (to be more friendly to edit & continues situation).
563  - style/opt: PopStyleVar could be optimized by having GetStyleVar returns the type, using a table mapping stylevar enum to data type.
564  - style: global scale setting.
565  - style: WindowPadding needs to be EVEN needs the 0.5 multiplier probably have a subtle effect on clip rectangle
566  - text: simple markup language for color change?
567  - font: dynamic font atlas to avoid baking huge ranges into bitmap and make scaling easier.
568  - font: small opt: for monospace font (like the defalt one) we can trim IndexXAdvance as long as trailing value is == FallbackXAdvance
569  - font: add support for kerning, probably optional. perhaps default to (32..128)^2 matrix ~ 36KB then hash fallback.
570  - font: add a simpler CalcTextSizeA() api? current one ok but not welcome if user needs to call it directly (without going through ImGui::CalcTextSize)
571  - font: fix AddRemapChar() to work before font has been built.
572  - log: LogButtons() options for specifying depth and/or hiding depth slider
573  - log: have more control over the log scope (e.g. stop logging when leaving current tree node scope)
574  - log: be able to log anything (e.g. right-click on a window/tree-node, shows context menu? log into tty/file/clipboard)
575  - log: let user copy any window content to clipboard easily (CTRL+C on windows? while moving it? context menu?). code is commented because it fails with multiple Begin/End pairs.
576  - filters: set a current filter that tree node can automatically query to hide themselves
577  - filters: handle wildcards (with implicit leading/trailing *), regexps
578  - shortcuts: add a shortcut api, e.g. parse "&Save" and/or "Save (CTRL+S)", pass in to widgets or provide simple ways to use (button=activate, input=focus)
579 !- keyboard: tooltip & combo boxes are messing up / not honoring keyboard tabbing
580  - keyboard: full keyboard navigation and focus. (#323)
581  - focus: preserve ActiveId/focus stack state, e.g. when opening a menu and close it, previously selected InputText() focus gets restored (#622)
582  - focus: SetKeyboardFocusHere() on with >= 0 offset could be done on same frame (else latch and modulate on beginning of next frame)
583  - input: rework IO system to be able to pass actual ordered/timestamped events. (~#335, #71)
584  - input: allow to decide and pass explicit double-clicks (e.g. for windows by the CS_DBLCLKS style).
585  - input: support track pad style scrolling & slider edit.
586  - misc: provide a way to compile out the entire implementation while providing a dummy API (e.g. #define IMGUI_DUMMY_IMPL)
587  - misc: double-clicking on title bar to minimize isn't consistent, perhaps move to single-click on left-most collapse icon?
588  - misc: provide HoveredTime and ActivatedTime to ease the creation of animations.
589  - style editor: have a more global HSV setter (e.g. alter hue on all elements). consider replacing active/hovered by offset in HSV space? (#438)
590  - style editor: color child window height expressed in multiple of line height.
591  - remote: make a system like RemoteImGui first-class citizen/project (#75)
592  - drawlist: move Font, FontSize, FontTexUvWhitePixel inside ImDrawList and make it self-contained (apart from drawing settings?)
593  - drawlist: end-user probably can't call Clear() directly because we expect a texture to be pushed in the stack.
594  - examples: directx9: save/restore device state more thoroughly.
595  - examples: window minimize, maximize (#583)
596  - optimization: add a flag to disable most of rendering, for the case where the user expect to skip it (#335)
597  - optimization: use another hash function than crc32, e.g. FNV1a
598  - optimization/render: merge command-lists with same clip-rect into one even if they aren't sequential? (as long as in-between clip rectangle don't overlap)?
599  - optimization: turn some the various stack vectors into statically-sized arrays
600  - optimization: better clipping for multi-component widgets
601 */
602 
603 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
604 #define _CRT_SECURE_NO_WARNINGS
605 #endif
606 
607 #include "imgui.h"
608 #define IMGUI_DEFINE_MATH_OPERATORS
609 #define IMGUI_DEFINE_PLACEMENT_NEW
610 #include "imgui_internal.h"
611 
612 #include <ctype.h> // toupper, isprint
613 #include <math.h> // sqrtf, fabsf, fmodf, powf, cosf, sinf, floorf, ceilf
614 #include <stdlib.h> // NULL, malloc, free, qsort, atoi
615 #include <stdio.h> // vsnprintf, sscanf, printf
616 #include <limits.h> // INT_MIN, INT_MAX
617 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
618 #include <stddef.h> // intptr_t
619 #else
620 #include <stdint.h> // intptr_t
621 #endif
622 
623 #ifdef _MSC_VER
624 #pragma warning (disable: 4127) // condition expression is constant
625 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
626 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
627 #endif
628 
629 // Clang warnings with -Weverything
630 #ifdef __clang__
631 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
632 #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
633 #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.
634 #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.
635 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
636 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
637 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int' //
638 #elif defined(__GNUC__)
639 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
640 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
641 #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
642 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
643 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
644 #endif
645 
646 //-------------------------------------------------------------------------
647 // Forward Declarations
648 //-------------------------------------------------------------------------
649 
650 static void LogRenderedText(const ImVec2& ref_pos, const char* text, const char* text_end = NULL);
651 
652 static void PushMultiItemsWidths(int components, float w_full = 0.0f);
653 static float GetDraggedColumnOffset(int column_index);
654 
655 static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
656 
657 static void SetCurrentFont(ImFont* font);
658 static void SetCurrentWindow(ImGuiWindow* window);
659 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
660 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiSetCond cond);
661 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiSetCond cond);
662 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiSetCond cond);
663 static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs);
665 static inline bool IsWindowContentHoverable(ImGuiWindow* window);
667 static void CheckStacksSize(ImGuiWindow* window, bool write);
668 static void Scrollbar(ImGuiWindow* window, bool horizontal);
669 
670 static void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_list, ImDrawList* draw_list);
671 static void AddWindowToRenderList(ImVector<ImDrawList*>& out_render_list, ImGuiWindow* window);
672 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>& out_sorted_windows, ImGuiWindow* window);
673 
674 static ImGuiIniData* FindWindowSettings(const char* name);
675 static ImGuiIniData* AddWindowSettings(const char* name);
676 static void LoadSettings();
677 static void SaveSettings();
678 static void MarkSettingsDirty();
679 
680 static void PushColumnClipRect(int column_index = -1);
681 static ImRect GetVisibleRect();
682 
683 static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags);
684 static void CloseInactivePopups();
685 static void ClosePopupToLevel(int remaining);
686 static void ClosePopup(ImGuiID id);
687 static bool IsPopupOpen(ImGuiID id);
689 static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& rect_to_avoid);
690 
692 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
693 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);
694 
695 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size);
696 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size);
697 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const void* value2);
698 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format);
699 
700 //-----------------------------------------------------------------------------
701 // Platform dependent default implementations
702 //-----------------------------------------------------------------------------
703 
704 static const char* GetClipboardTextFn_DefaultImpl();
705 static void SetClipboardTextFn_DefaultImpl(const char* text);
706 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
707 
708 //-----------------------------------------------------------------------------
709 // Context
710 //-----------------------------------------------------------------------------
711 
712 // Default context, default font atlas.
713 // New contexts always point by default to this font atlas. It can be changed by reassigning the GetIO().Fonts variable.
716 
717 // Current context pointer. Implicitely used by all ImGui functions. Always assumed to be != NULL. Change to a different context by calling ImGui::SetCurrentContext()
718 // 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 (A) having two instances of the ImGui code under different namespaces or (B) change this variable to be TLS. Further development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
720 
721 //-----------------------------------------------------------------------------
722 // User facing structures
723 //-----------------------------------------------------------------------------
724 
726 {
727  Alpha = 1.0f; // Global alpha applies to everything in ImGui
728  WindowPadding = ImVec2(8,8); // Padding within a window
729  WindowMinSize = ImVec2(32,32); // Minimum window size
730  WindowRounding = 9.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows
731  WindowTitleAlign = ImGuiAlign_Left; // Alignment for title bar text
732  ChildWindowRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
733  FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
734  FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
735  ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
736  ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
737  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!
738  IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
739  ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
740  ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
741  ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
742  GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
743  GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
744  DisplayWindowPadding = ImVec2(22,22); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
745  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.
746  AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
747  AntiAliasedShapes = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
748  CurveTessellationTol = 1.25f; // Tessellation tolerance. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
749 
750  Colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
751  Colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
752  Colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f);
753  Colors[ImGuiCol_ChildWindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
754  Colors[ImGuiCol_PopupBg] = ImVec4(0.05f, 0.05f, 0.10f, 0.90f);
755  Colors[ImGuiCol_Border] = ImVec4(0.70f, 0.70f, 0.70f, 0.65f);
756  Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
757  Colors[ImGuiCol_FrameBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.30f); // Background of checkbox, radio button, plot, slider, text input
758  Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.90f, 0.80f, 0.80f, 0.40f);
759  Colors[ImGuiCol_FrameBgActive] = ImVec4(0.90f, 0.65f, 0.65f, 0.45f);
760  Colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.27f, 0.54f, 0.83f);
761  Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.40f, 0.40f, 0.80f, 0.20f);
762  Colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.32f, 0.63f, 0.87f);
763  Colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.40f, 0.55f, 0.80f);
764  Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.20f, 0.25f, 0.30f, 0.60f);
765  Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.40f, 0.40f, 0.80f, 0.30f);
766  Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.40f, 0.80f, 0.40f);
767  Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 0.40f);
768  Colors[ImGuiCol_ComboBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.99f);
769  Colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f);
770  Colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
771  Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f);
772  Colors[ImGuiCol_Button] = ImVec4(0.67f, 0.40f, 0.40f, 0.60f);
773  Colors[ImGuiCol_ButtonHovered] = ImVec4(0.67f, 0.40f, 0.40f, 1.00f);
774  Colors[ImGuiCol_ButtonActive] = ImVec4(0.80f, 0.50f, 0.50f, 1.00f);
775  Colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
776  Colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
777  Colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
778  Colors[ImGuiCol_Column] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
779  Colors[ImGuiCol_ColumnHovered] = ImVec4(0.70f, 0.60f, 0.60f, 1.00f);
780  Colors[ImGuiCol_ColumnActive] = ImVec4(0.90f, 0.70f, 0.70f, 1.00f);
781  Colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f);
782  Colors[ImGuiCol_ResizeGripHovered] = ImVec4(1.00f, 1.00f, 1.00f, 0.60f);
783  Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.90f);
784  Colors[ImGuiCol_CloseButton] = ImVec4(0.50f, 0.50f, 0.90f, 0.50f);
785  Colors[ImGuiCol_CloseButtonHovered] = ImVec4(0.70f, 0.70f, 0.90f, 0.60f);
786  Colors[ImGuiCol_CloseButtonActive] = ImVec4(0.70f, 0.70f, 0.70f, 1.00f);
787  Colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
788  Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
789  Colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
790  Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
791  Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
792  Colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
793 }
794 
796 {
797  // Most fields are initialized with zero
798  memset(this, 0, sizeof(*this));
799 
800  DisplaySize = ImVec2(-1.0f, -1.0f);
801  DeltaTime = 1.0f/60.0f;
802  IniSavingRate = 5.0f;
803  IniFilename = "imgui.ini";
804  LogFilename = "imgui_log.txt";
805  Fonts = &GImDefaultFontAtlas;
806  FontGlobalScale = 1.0f;
807  DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
808  MousePos = ImVec2(-1,-1);
809  MousePosPrev = ImVec2(-1,-1);
810  MouseDoubleClickTime = 0.30f;
811  MouseDoubleClickMaxDist = 6.0f;
812  MouseDragThreshold = 6.0f;
813  for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++)
814  MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
815  for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++)
816  KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f;
817  for (int i = 0; i < ImGuiKey_COUNT; i++)
818  KeyMap[i] = -1;
819  KeyRepeatDelay = 0.250f;
820  KeyRepeatRate = 0.050f;
821  UserData = NULL;
822 
823  // User functions
824  RenderDrawListsFn = NULL;
825  MemAllocFn = malloc;
826  MemFreeFn = free;
827  GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
828  SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
829  ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
830 
831  // Set OS X style defaults based on __APPLE__ compile time flag
832 #ifdef __APPLE__
833  WordMovementUsesAltKey = true; // OS X style: Text editing cursor movement using Alt instead of Ctrl
834  ShortcutsUseSuperKey = true; // OS X style: Shortcuts using Cmd/Super instead of Ctrl
835  DoubleClickSelectsWord = true; // OS X style: Double click selects by word instead of selecting whole text
836  MultiSelectUsesSuperKey = true; // OS X style: Multi-selection in lists uses Cmd/Super instead of Ctrl
837 #endif
838 }
839 
840 // Pass in translated ASCII characters for text input.
841 // - with glfw you can get those from the callback set in glfwSetCharCallback()
842 // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
844 {
845  const int n = ImStrlenW(InputCharacters);
846  if (n + 1 < IM_ARRAYSIZE(InputCharacters))
847  {
848  InputCharacters[n] = c;
849  InputCharacters[n+1] = '\0';
850  }
851 }
852 
853 void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
854 {
855  // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more
856  const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar);
857  ImWchar wchars[wchars_buf_len];
858  ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL);
859  for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++)
860  AddInputCharacter(wchars[i]);
861 }
862 
863 //-----------------------------------------------------------------------------
864 // HELPERS
865 //-----------------------------------------------------------------------------
866 
867 #define IM_F32_TO_INT8(_VAL) ((int)((_VAL) * 255.0f + 0.5f))
868 
869 // Play it nice with Windows users. Notepad in 2015 still doesn't display text data with Unix-style \n.
870 #ifdef _WIN32
871 #define IM_NEWLINE "\r\n"
872 #else
873 #define IM_NEWLINE "\n"
874 #endif
875 
876 bool ImIsPointInTriangle(const ImVec2& p, const ImVec2& a, const ImVec2& b, const ImVec2& c)
877 {
878  bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
879  bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
880  bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
881  return ((b1 == b2) && (b2 == b3));
882 }
883 
884 int ImStricmp(const char* str1, const char* str2)
885 {
886  int d;
887  while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
888  return d;
889 }
890 
891 int ImStrnicmp(const char* str1, const char* str2, int count)
892 {
893  int d = 0;
894  while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
895  return d;
896 }
897 
898 char* ImStrdup(const char *str)
899 {
900  size_t len = strlen(str) + 1;
901  void* buff = ImGui::MemAlloc(len);
902  return (char*)memcpy(buff, (const void*)str, len);
903 }
904 
905 int ImStrlenW(const ImWchar* str)
906 {
907  int n = 0;
908  while (*str++) n++;
909  return n;
910 }
911 
912 const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
913 {
914  while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
915  buf_mid_line--;
916  return buf_mid_line;
917 }
918 
919 const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
920 {
921  if (!needle_end)
922  needle_end = needle + strlen(needle);
923 
924  const char un0 = (char)toupper(*needle);
925  while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
926  {
927  if (toupper(*haystack) == un0)
928  {
929  const char* b = needle + 1;
930  for (const char* a = haystack + 1; b < needle_end; a++, b++)
931  if (toupper(*a) != toupper(*b))
932  break;
933  if (b == needle_end)
934  return haystack;
935  }
936  haystack++;
937  }
938  return NULL;
939 }
940 
941 int ImFormatString(char* buf, int buf_size, const char* fmt, ...)
942 {
943  va_list args;
944  va_start(args, fmt);
945  int w = vsnprintf(buf, buf_size, fmt, args);
946  va_end(args);
947  buf[buf_size-1] = 0;
948  return (w == -1) ? buf_size : w;
949 }
950 
951 int ImFormatStringV(char* buf, int buf_size, const char* fmt, va_list args)
952 {
953  int w = vsnprintf(buf, buf_size, fmt, args);
954  buf[buf_size-1] = 0;
955  return (w == -1) ? buf_size : w;
956 }
957 
958 // Pass data_size==0 for zero-terminated strings
959 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
960 ImU32 ImHash(const void* data, int data_size, ImU32 seed)
961 {
962  static ImU32 crc32_lut[256] = { 0 };
963  if (!crc32_lut[1])
964  {
965  const ImU32 polynomial = 0xEDB88320;
966  for (ImU32 i = 0; i < 256; i++)
967  {
968  ImU32 crc = i;
969  for (ImU32 j = 0; j < 8; j++)
970  crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial);
971  crc32_lut[i] = crc;
972  }
973  }
974 
975  seed = ~seed;
976  ImU32 crc = seed;
977  const unsigned char* current = (const unsigned char*)data;
978 
979  if (data_size > 0)
980  {
981  // Known size
982  while (data_size--)
983  crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++];
984  }
985  else
986  {
987  // Zero-terminated string
988  while (unsigned char c = *current++)
989  {
990  // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
991  // Because this syntax is rarely used we are optimizing for the common case.
992  // - If we reach ### in the string we discard the hash so far and reset to the seed.
993  // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
994  if (c == '#' && current[0] == '#' && current[1] == '#')
995  crc = seed;
996 
997  crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
998  }
999  }
1000  return ~crc;
1001 }
1002 
1003 //-----------------------------------------------------------------------------
1004 // ImText* helpers
1005 //-----------------------------------------------------------------------------
1006 
1007 // Convert UTF-8 to 32-bits character, process single character input.
1008 // Based on stb_from_utf8() from github.com/nothings/stb/
1009 // We handle UTF-8 decoding error by skipping forward.
1010 int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
1011 {
1012  unsigned int c = (unsigned int)-1;
1013  const unsigned char* str = (const unsigned char*)in_text;
1014  if (!(*str & 0x80))
1015  {
1016  c = (unsigned int)(*str++);
1017  *out_char = c;
1018  return 1;
1019  }
1020  if ((*str & 0xe0) == 0xc0)
1021  {
1022  *out_char = 0xFFFD; // will be invalid but not end of string
1023  if (in_text_end && in_text_end - (const char*)str < 2) return 1;
1024  if (*str < 0xc2) return 2;
1025  c = (unsigned int)((*str++ & 0x1f) << 6);
1026  if ((*str & 0xc0) != 0x80) return 2;
1027  c += (*str++ & 0x3f);
1028  *out_char = c;
1029  return 2;
1030  }
1031  if ((*str & 0xf0) == 0xe0)
1032  {
1033  *out_char = 0xFFFD; // will be invalid but not end of string
1034  if (in_text_end && in_text_end - (const char*)str < 3) return 1;
1035  if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
1036  if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
1037  c = (unsigned int)((*str++ & 0x0f) << 12);
1038  if ((*str & 0xc0) != 0x80) return 3;
1039  c += (unsigned int)((*str++ & 0x3f) << 6);
1040  if ((*str & 0xc0) != 0x80) return 3;
1041  c += (*str++ & 0x3f);
1042  *out_char = c;
1043  return 3;
1044  }
1045  if ((*str & 0xf8) == 0xf0)
1046  {
1047  *out_char = 0xFFFD; // will be invalid but not end of string
1048  if (in_text_end && in_text_end - (const char*)str < 4) return 1;
1049  if (*str > 0xf4) return 4;
1050  if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
1051  if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
1052  c = (unsigned int)((*str++ & 0x07) << 18);
1053  if ((*str & 0xc0) != 0x80) return 4;
1054  c += (unsigned int)((*str++ & 0x3f) << 12);
1055  if ((*str & 0xc0) != 0x80) return 4;
1056  c += (unsigned int)((*str++ & 0x3f) << 6);
1057  if ((*str & 0xc0) != 0x80) return 4;
1058  c += (*str++ & 0x3f);
1059  // utf-8 encodings of values used in surrogate pairs are invalid
1060  if ((c & 0xFFFFF800) == 0xD800) return 4;
1061  *out_char = c;
1062  return 4;
1063  }
1064  *out_char = 0;
1065  return 0;
1066 }
1068 int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
1069 {
1070  ImWchar* buf_out = buf;
1071  ImWchar* buf_end = buf + buf_size;
1072  while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1073  {
1074  unsigned int c;
1075  in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1076  if (c == 0)
1077  break;
1078  if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
1079  *buf_out++ = (ImWchar)c;
1080  }
1081  *buf_out = 0;
1082  if (in_text_remaining)
1083  *in_text_remaining = in_text;
1084  return (int)(buf_out - buf);
1085 }
1086 
1087 int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
1088 {
1089  int char_count = 0;
1090  while ((!in_text_end || in_text < in_text_end) && *in_text)
1091  {
1092  unsigned int c;
1093  in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1094  if (c == 0)
1095  break;
1096  if (c < 0x10000)
1097  char_count++;
1098  }
1099  return char_count;
1100 }
1101 
1102 // Based on stb_to_utf8() from github.com/nothings/stb/
1103 static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
1104 {
1105  if (c < 0x80)
1106  {
1107  buf[0] = (char)c;
1108  return 1;
1109  }
1110  if (c < 0x800)
1111  {
1112  if (buf_size < 2) return 0;
1113  buf[0] = (char)(0xc0 + (c >> 6));
1114  buf[1] = (char)(0x80 + (c & 0x3f));
1115  return 2;
1116  }
1117  if (c >= 0xdc00 && c < 0xe000)
1118  {
1119  return 0;
1120  }
1121  if (c >= 0xd800 && c < 0xdc00)
1122  {
1123  if (buf_size < 4) return 0;
1124  buf[0] = (char)(0xf0 + (c >> 18));
1125  buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
1126  buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
1127  buf[3] = (char)(0x80 + ((c ) & 0x3f));
1128  return 4;
1129  }
1130  //else if (c < 0x10000)
1131  {
1132  if (buf_size < 3) return 0;
1133  buf[0] = (char)(0xe0 + (c >> 12));
1134  buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
1135  buf[2] = (char)(0x80 + ((c ) & 0x3f));
1136  return 3;
1137  }
1138 }
1139 
1140 static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
1141 {
1142  if (c < 0x80) return 1;
1143  if (c < 0x800) return 2;
1144  if (c >= 0xdc00 && c < 0xe000) return 0;
1145  if (c >= 0xd800 && c < 0xdc00) return 4;
1146  return 3;
1147 }
1148 
1149 int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
1150 {
1151  char* buf_out = buf;
1152  const char* buf_end = buf + buf_size;
1153  while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1154  {
1155  unsigned int c = (unsigned int)(*in_text++);
1156  if (c < 0x80)
1157  *buf_out++ = (char)c;
1158  else
1159  buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c);
1160  }
1161  *buf_out = 0;
1162  return (int)(buf_out - buf);
1163 }
1164 
1165 int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
1166 {
1167  int bytes_count = 0;
1168  while ((!in_text_end || in_text < in_text_end) && *in_text)
1169  {
1170  unsigned int c = (unsigned int)(*in_text++);
1171  if (c < 0x80)
1172  bytes_count++;
1173  else
1174  bytes_count += ImTextCountUtf8BytesFromChar(c);
1175  }
1176  return bytes_count;
1177 }
1178 
1180 {
1181  float s = 1.0f/255.0f;
1182  return ImVec4((in & 0xFF) * s, ((in >> 8) & 0xFF) * s, ((in >> 16) & 0xFF) * s, (in >> 24) * s);
1183 }
1184 
1186 {
1187  ImU32 out;
1188  out = ((ImU32)IM_F32_TO_INT8(ImSaturate(in.x)));
1189  out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.y))) << 8;
1190  out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.z))) << 16;
1191  out |= ((ImU32)IM_F32_TO_INT8(ImSaturate(in.w))) << 24;
1192  return out;
1193 }
1194 
1195 // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
1196 // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
1197 void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
1198 {
1199  float K = 0.f;
1200  if (g < b)
1201  {
1202  const float tmp = g; g = b; b = tmp;
1203  K = -1.f;
1204  }
1205  if (r < g)
1206  {
1207  const float tmp = r; r = g; g = tmp;
1208  K = -2.f / 6.f - K;
1209  }
1210 
1211  const float chroma = r - (g < b ? g : b);
1212  out_h = fabsf(K + (g - b) / (6.f * chroma + 1e-20f));
1213  out_s = chroma / (r + 1e-20f);
1214  out_v = r;
1215 }
1216 
1217 // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
1218 // also http://en.wikipedia.org/wiki/HSL_and_HSV
1219 void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
1220 {
1221  if (s == 0.0f)
1222  {
1223  // gray
1224  out_r = out_g = out_b = v;
1225  return;
1226  }
1227 
1228  h = fmodf(h, 1.0f) / (60.0f/360.0f);
1229  int i = (int)h;
1230  float f = h - (float)i;
1231  float p = v * (1.0f - s);
1232  float q = v * (1.0f - s * f);
1233  float t = v * (1.0f - s * (1.0f - f));
1234 
1235  switch (i)
1236  {
1237  case 0: out_r = v; out_g = t; out_b = p; break;
1238  case 1: out_r = q; out_g = v; out_b = p; break;
1239  case 2: out_r = p; out_g = v; out_b = t; break;
1240  case 3: out_r = p; out_g = q; out_b = v; break;
1241  case 4: out_r = t; out_g = p; out_b = v; break;
1242  case 5: default: out_r = v; out_g = p; out_b = q; break;
1243  }
1244 }
1245 
1246 // Load file content into memory
1247 // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
1248 void* ImLoadFileToMemory(const char* filename, const char* file_open_mode, int* out_file_size, int padding_bytes)
1249 {
1250  IM_ASSERT(filename && file_open_mode);
1251  if (out_file_size)
1252  *out_file_size = 0;
1253 
1254  FILE* f;
1255  if ((f = fopen(filename, file_open_mode)) == NULL)
1256  return NULL;
1257 
1258  long file_size_signed;
1259  if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
1260  {
1261  fclose(f);
1262  return NULL;
1263  }
1264 
1265  int file_size = (int)file_size_signed;
1266  void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
1267  if (file_data == NULL)
1268  {
1269  fclose(f);
1270  return NULL;
1271  }
1272  if (fread(file_data, 1, (size_t)file_size, f) != (size_t)file_size)
1273  {
1274  fclose(f);
1275  ImGui::MemFree(file_data);
1276  return NULL;
1277  }
1278  if (padding_bytes > 0)
1279  memset((void *)(((char*)file_data) + file_size), 0, padding_bytes);
1280 
1281  fclose(f);
1282  if (out_file_size)
1283  *out_file_size = file_size;
1284 
1285  return file_data;
1287 
1288 //-----------------------------------------------------------------------------
1289 // ImGuiStorage
1290 //-----------------------------------------------------------------------------
1291 
1292 // Helper: Key->value storage
1294 {
1295  Data.clear();
1296 }
1298 // std::lower_bound but without the bullshit
1300 {
1303  int count = (int)(last - first);
1304  while (count > 0)
1305  {
1306  int count2 = count / 2;
1307  ImVector<ImGuiStorage::Pair>::iterator mid = first + count2;
1308  if (mid->key < key)
1309  {
1310  first = ++mid;
1311  count -= count2 + 1;
1312  }
1313  else
1314  {
1315  count = count2;
1316  }
1317  }
1318  return first;
1319 }
1320 
1321 int ImGuiStorage::GetInt(ImU32 key, int default_val) const
1322 {
1324  if (it == Data.end() || it->key != key)
1325  return default_val;
1326  return it->val_i;
1327 }
1328 
1329 bool ImGuiStorage::GetBool(ImU32 key, bool default_val) const
1330 {
1331  return GetInt(key, default_val ? 1 : 0) != 0;
1332 }
1333 
1334 float ImGuiStorage::GetFloat(ImU32 key, float default_val) const
1335 {
1337  if (it == Data.end() || it->key != key)
1338  return default_val;
1339  return it->val_f;
1340 }
1341 
1343 {
1345  if (it == Data.end() || it->key != key)
1346  return NULL;
1347  return it->val_p;
1348 }
1349 
1350 // 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.
1351 int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
1352 {
1353  ImVector<Pair>::iterator it = LowerBound(Data, key);
1354  if (it == Data.end() || it->key != key)
1355  it = Data.insert(it, Pair(key, default_val));
1356  return &it->val_i;
1357 }
1358 
1359 bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
1360 {
1361  return (bool*)GetIntRef(key, default_val ? 1 : 0);
1362 }
1363 
1364 float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
1365 {
1366  ImVector<Pair>::iterator it = LowerBound(Data, key);
1367  if (it == Data.end() || it->key != key)
1368  it = Data.insert(it, Pair(key, default_val));
1369  return &it->val_f;
1370 }
1371 
1372 void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
1373 {
1374  ImVector<Pair>::iterator it = LowerBound(Data, key);
1375  if (it == Data.end() || it->key != key)
1376  it = Data.insert(it, Pair(key, default_val));
1377  return &it->val_p;
1378 }
1379 
1380 // 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)
1382 {
1383  ImVector<Pair>::iterator it = LowerBound(Data, key);
1384  if (it == Data.end() || it->key != key)
1385  {
1386  Data.insert(it, Pair(key, val));
1387  return;
1388  }
1389  it->val_i = val;
1390 }
1391 
1393 {
1394  SetInt(key, val ? 1 : 0);
1395 }
1396 
1398 {
1399  ImVector<Pair>::iterator it = LowerBound(Data, key);
1400  if (it == Data.end() || it->key != key)
1401  {
1402  Data.insert(it, Pair(key, val));
1403  return;
1404  }
1405  it->val_f = val;
1406 }
1407 
1409 {
1410  ImVector<Pair>::iterator it = LowerBound(Data, key);
1411  if (it == Data.end() || it->key != key)
1412  {
1413  Data.insert(it, Pair(key, val));
1414  return;
1415  }
1416  it->val_p = val;
1417 }
1418 
1420 {
1421  for (int i = 0; i < Data.Size; i++)
1422  Data[i].val_i = v;
1423 }
1424 
1425 //-----------------------------------------------------------------------------
1426 // ImGuiTextFilter
1427 //-----------------------------------------------------------------------------
1428 
1429 // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
1430 ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
1431 {
1432  if (default_filter)
1433  {
1434  ImFormatString(InputBuf, IM_ARRAYSIZE(InputBuf), "%s", default_filter);
1435  Build();
1436  }
1437  else
1438  {
1439  InputBuf[0] = 0;
1440  CountGrep = 0;
1441  }
1442 }
1443 
1444 bool ImGuiTextFilter::Draw(const char* label, float width)
1445 {
1446  if (width != 0.0f)
1447  ImGui::PushItemWidth(width);
1448  bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
1449  if (width != 0.0f)
1451  if (value_changed)
1452  Build();
1453  return value_changed;
1454 }
1455 
1457 {
1458  out.resize(0);
1459  const char* wb = b;
1460  const char* we = wb;
1461  while (we < e)
1462  {
1463  if (*we == separator)
1464  {
1465  out.push_back(TextRange(wb, we));
1466  wb = we + 1;
1467  }
1468  we++;
1469  }
1470  if (wb != we)
1471  out.push_back(TextRange(wb, we));
1472 }
1473 
1475 {
1476  Filters.resize(0);
1477  TextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
1478  input_range.split(',', Filters);
1479 
1480  CountGrep = 0;
1481  for (int i = 0; i != Filters.Size; i++)
1482  {
1483  Filters[i].trim_blanks();
1484  if (Filters[i].empty())
1485  continue;
1486  if (Filters[i].front() != '-')
1487  CountGrep += 1;
1488  }
1489 }
1490 
1491 bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
1492 {
1493  if (Filters.empty())
1494  return true;
1495 
1496  if (text == NULL)
1497  text = "";
1498 
1499  for (int i = 0; i != Filters.Size; i++)
1500  {
1501  const TextRange& f = Filters[i];
1502  if (f.empty())
1503  continue;
1504  if (f.front() == '-')
1505  {
1506  // Subtract
1507  if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL)
1508  return false;
1509  }
1510  else
1511  {
1512  // Grep
1513  if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)
1514  return true;
1515  }
1516  }
1517 
1518  // Implicit * grep
1519  if (CountGrep == 0)
1520  return true;
1521 
1522  return false;
1523 }
1524 
1525 //-----------------------------------------------------------------------------
1526 // ImGuiTextBuffer
1527 //-----------------------------------------------------------------------------
1528 
1529 // On some platform vsnprintf() takes va_list by reference and modifies it.
1530 // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
1531 #ifndef va_copy
1532 #define va_copy(dest, src) (dest = src)
1533 #endif
1534 
1535 // Helper: Text buffer for logging/accumulating text
1536 void ImGuiTextBuffer::appendv(const char* fmt, va_list args)
1537 {
1538  va_list args_copy;
1539  va_copy(args_copy, args);
1540 
1541  int len = vsnprintf(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
1542  if (len <= 0)
1543  return;
1544 
1545  const int write_off = Buf.Size;
1546  const int needed_sz = write_off + len;
1547  if (write_off + len >= Buf.Capacity)
1548  {
1549  int double_capacity = Buf.Capacity * 2;
1550  Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity);
1551  }
1552 
1553  Buf.resize(needed_sz);
1554  ImFormatStringV(&Buf[write_off] - 1, len+1, fmt, args_copy);
1555 }
1556 
1557 void ImGuiTextBuffer::append(const char* fmt, ...)
1558 {
1559  va_list args;
1560  va_start(args, fmt);
1561  appendv(fmt, args);
1562  va_end(args);
1563 }
1564 
1565 //-----------------------------------------------------------------------------
1566 // ImGuiSimpleColumns
1567 //-----------------------------------------------------------------------------
1568 
1570 {
1571  Count = 0;
1572  Spacing = Width = NextWidth = 0.0f;
1573  memset(Pos, 0, sizeof(Pos));
1574  memset(NextWidths, 0, sizeof(NextWidths));
1575 }
1576 
1577 void ImGuiSimpleColumns::Update(int count, float spacing, bool clear)
1578 {
1579  IM_ASSERT(Count <= IM_ARRAYSIZE(Pos));
1580  Count = count;
1581  Width = NextWidth = 0.0f;
1582  Spacing = spacing;
1583  if (clear) memset(NextWidths, 0, sizeof(NextWidths));
1584  for (int i = 0; i < Count; i++)
1585  {
1586  if (i > 0 && NextWidths[i] > 0.0f)
1587  Width += Spacing;
1588  Pos[i] = (float)(int)Width;
1589  Width += NextWidths[i];
1590  NextWidths[i] = 0.0f;
1591  }
1592 }
1593 
1594 float ImGuiSimpleColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double
1595 {
1596  NextWidth = 0.0f;
1597  NextWidths[0] = ImMax(NextWidths[0], w0);
1598  NextWidths[1] = ImMax(NextWidths[1], w1);
1599  NextWidths[2] = ImMax(NextWidths[2], w2);
1600  for (int i = 0; i < 3; i++)
1601  NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f);
1602  return ImMax(Width, NextWidth);
1603 }
1604 
1606 {
1607  return ImMax(0.0f, avail_w - Width);
1608 }
1609 
1610 //-----------------------------------------------------------------------------
1611 // ImGuiListClipper
1612 //-----------------------------------------------------------------------------
1613 
1614 static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
1615 {
1616  // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
1617  // 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.
1618  ImGui::SetCursorPosY(pos_y);
1620  window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height;
1621  window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y);
1622 }
1623 
1624 // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
1625 // Use case B: Begin() called from constructor with items_height>0
1626 // 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.
1627 void ImGuiListClipper::Begin(int count, float items_height)
1628 {
1629  StartPosY = ImGui::GetCursorPosY();
1630  ItemsHeight = items_height;
1631  ItemsCount = count;
1632  StepNo = 0;
1633  DisplayEnd = DisplayStart = -1;
1634  if (ItemsHeight > 0.0f)
1635  {
1636  ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
1637  if (DisplayStart > 0)
1638  SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
1639  StepNo = 2;
1640  }
1641 }
1642 
1644 {
1645  if (ItemsCount < 0)
1646  return;
1647  // 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.
1648  if (ItemsCount < INT_MAX)
1649  SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
1650  ItemsCount = -1;
1651  StepNo = 3;
1652 }
1653 
1655 {
1656  if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
1657  {
1658  ItemsCount = -1;
1659  return false;
1660  }
1661  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.
1662  {
1663  DisplayStart = 0;
1664  DisplayEnd = 1;
1665  StartPosY = ImGui::GetCursorPosY();
1666  StepNo = 1;
1667  return true;
1668  }
1669  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.
1670  {
1671  if (ItemsCount == 1) { ItemsCount = -1; return false; }
1672  float items_height = ImGui::GetCursorPosY() - StartPosY;
1673  IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically
1674  ImGui::SetCursorPosY(StartPosY); // Rewind cursor so we can Begin() again, this time with a known height.
1675  Begin(ItemsCount, items_height);
1676  StepNo = 3;
1677  return true;
1678  }
1679  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.
1680  {
1681  IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
1682  StepNo = 3;
1683  return true;
1684  }
1685  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.
1686  End();
1687  return false;
1688 }
1689 
1690 //-----------------------------------------------------------------------------
1691 // ImGuiWindow
1692 //-----------------------------------------------------------------------------
1693 
1695 {
1696  Name = ImStrdup(name);
1697  ID = ImHash(name, 0);
1698  IDStack.push_back(ID);
1699  MoveID = GetID("#MOVE");
1700 
1701  Flags = 0;
1702  IndexWithinParent = 0;
1703  PosFloat = Pos = ImVec2(0.0f, 0.0f);
1704  Size = SizeFull = ImVec2(0.0f, 0.0f);
1705  SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
1706  WindowPadding = ImVec2(0.0f, 0.0f);
1707  Scroll = ImVec2(0.0f, 0.0f);
1708  ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
1709  ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
1710  ScrollbarX = ScrollbarY = false;
1711  ScrollbarSizes = ImVec2(0.0f, 0.0f);
1712  BorderSize = 0.0f;
1713  Active = WasActive = false;
1714  Accessed = false;
1715  Collapsed = false;
1716  SkipItems = false;
1717  BeginCount = 0;
1718  PopupID = 0;
1719  AutoFitFramesX = AutoFitFramesY = -1;
1720  AutoFitOnlyGrows = false;
1721  AutoPosLastDirection = -1;
1722  HiddenFrames = 0;
1723  SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiSetCond_Always | ImGuiSetCond_Once | ImGuiSetCond_FirstUseEver | ImGuiSetCond_Appearing;
1724  SetWindowPosCenterWanted = false;
1725 
1726  LastFrameActive = -1;
1727  ItemWidthDefault = 0.0f;
1728  FontWindowScale = 1.0f;
1729 
1730  DrawList = (ImDrawList*)ImGui::MemAlloc(sizeof(ImDrawList));
1731  IM_PLACEMENT_NEW(DrawList) ImDrawList();
1732  DrawList->_OwnerName = Name;
1733  RootWindow = NULL;
1734  RootNonPopupWindow = NULL;
1735  ParentWindow = NULL;
1736 
1737  FocusIdxAllCounter = FocusIdxTabCounter = -1;
1738  FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX;
1739  FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX;
1740 }
1741 
1743 {
1744  DrawList->~ImDrawList();
1745  ImGui::MemFree(DrawList);
1746  DrawList = NULL;
1747  ImGui::MemFree(Name);
1748  Name = NULL;
1749 }
1750 
1751 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
1752 {
1753  ImGuiID seed = IDStack.back();
1754  ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
1755  ImGui::KeepAliveID(id);
1756  return id;
1757 }
1758 
1759 ImGuiID ImGuiWindow::GetID(const void* ptr)
1760 {
1761  ImGuiID seed = IDStack.back();
1762  ImGuiID id = ImHash(&ptr, sizeof(void*), seed);
1763  ImGui::KeepAliveID(id);
1764  return id;
1765 }
1766 
1767 //-----------------------------------------------------------------------------
1768 // Internal API exposed in imgui_internal.h
1769 //-----------------------------------------------------------------------------
1770 
1772 {
1773  ImGuiContext& g = *GImGui;
1774  g.CurrentWindow = window;
1775  if (window)
1776  g.FontSize = window->CalcFontSize();
1777 }
1778 
1780 {
1781  ImGuiContext& g = *GImGui;
1783  return g.CurrentWindowStack[(unsigned int)g.CurrentWindowStack.Size - 2];
1784 }
1785 
1787 {
1788  ImGuiContext& g = *GImGui;
1789  g.ActiveId = id;
1790  g.ActiveIdAllowOverlap = false;
1791  g.ActiveIdIsJustActivated = true;
1792  g.ActiveIdWindow = window;
1793 }
1794 
1796 {
1797  ImGuiContext& g = *GImGui;
1798  g.HoveredId = id;
1799  g.HoveredIdAllowOverlap = false;
1800 }
1801 
1803 {
1804  ImGuiContext& g = *GImGui;
1805  if (g.ActiveId == id)
1806  g.ActiveIdIsAlive = true;
1807 }
1808 
1809 // Advance cursor given item size for layout.
1810 void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
1811 {
1813  if (window->SkipItems)
1814  return;
1815 
1816  // Always align ourselves on pixel boundaries
1817  ImGuiContext& g = *GImGui;
1818  const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
1819  const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
1820  window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
1821  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));
1822  window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
1823  window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
1824 
1825  //window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, 0xFF0000FF, 4); // Debug
1826 
1827  window->DC.PrevLineHeight = line_height;
1828  window->DC.PrevLineTextBaseOffset = text_base_offset;
1829  window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f;
1830 }
1831 
1832 void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
1833 {
1834  ItemSize(bb.GetSize(), text_offset_y);
1835 }
1836 
1837 // Declare item bounding box for clipping and interaction.
1838 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
1839 // declares their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
1840 bool ImGui::ItemAdd(const ImRect& bb, const ImGuiID* id)
1841 {
1843  window->DC.LastItemID = id ? *id : 0;
1844  window->DC.LastItemRect = bb;
1845  window->DC.LastItemHoveredAndUsable = window->DC.LastItemHoveredRect = false;
1846  if (IsClippedEx(bb, id, false))
1847  return false;
1848 
1849  // This is a sensible default, but widgets are free to override it after calling ItemAdd()
1850  ImGuiContext& g = *GImGui;
1851  if (IsMouseHoveringRect(bb.Min, bb.Max))
1852  {
1853  // Matching the behavior of IsHovered() but allow if ActiveId==window->MoveID (we clicked on the window background)
1854  // So that clicking on items with no active id such as Text() still returns true with IsItemHovered()
1855  window->DC.LastItemHoveredRect = true;
1856  if (g.HoveredRootWindow == window->RootWindow)
1857  if (g.ActiveId == 0 || (id && g.ActiveId == *id) || g.ActiveIdAllowOverlap || (g.ActiveId == window->MoveID))
1858  if (IsWindowContentHoverable(window))
1859  window->DC.LastItemHoveredAndUsable = true;
1860  }
1861 
1862  return true;
1863 }
1864 
1865 bool ImGui::IsClippedEx(const ImRect& bb, const ImGuiID* id, bool clip_even_when_logged)
1866 {
1867  ImGuiContext& g = *GImGui;
1869 
1870  if (!bb.Overlaps(window->ClipRect))
1871  if (!id || *id != GImGui->ActiveId)
1872  if (clip_even_when_logged || !g.LogEnabled)
1873  return true;
1874  return false;
1875 }
1876 
1877 // NB: This is an internal helper. The user-facing IsItemHovered() is using data emitted from ItemAdd(), with a slightly different logic.
1878 bool ImGui::IsHovered(const ImRect& bb, ImGuiID id, bool flatten_childs)
1879 {
1880  ImGuiContext& g = *GImGui;
1881  if (g.HoveredId == 0 || g.HoveredId == id || g.HoveredIdAllowOverlap)
1882  {
1884  if (g.HoveredWindow == window || (flatten_childs && g.HoveredRootWindow == window->RootWindow))
1885  if ((g.ActiveId == 0 || g.ActiveId == id || g.ActiveIdAllowOverlap) && IsMouseHoveringRect(bb.Min, bb.Max))
1887  return true;
1888  }
1889  return false;
1890 }
1891 
1892 bool ImGui::FocusableItemRegister(ImGuiWindow* window, bool is_active, bool tab_stop)
1893 {
1894  ImGuiContext& g = *GImGui;
1895 
1896  const bool allow_keyboard_focus = window->DC.AllowKeyboardFocus;
1897  window->FocusIdxAllCounter++;
1898  if (allow_keyboard_focus)
1899  window->FocusIdxTabCounter++;
1900 
1901  // Process keyboard input at this point: TAB, Shift-TAB switch focus
1902  // We can always TAB out of a widget that doesn't allow tabbing in.
1903  if (tab_stop && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && is_active && IsKeyPressedMap(ImGuiKey_Tab))
1904  {
1905  // Modulo on index will be applied at the end of frame once we've got the total counter of items.
1906  window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1);
1907  }
1908 
1909  if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent)
1910  return true;
1911 
1912  if (allow_keyboard_focus)
1913  if (window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent)
1914  return true;
1915 
1916  return false;
1917 }
1918 
1920 {
1921  window->FocusIdxAllCounter--;
1922  window->FocusIdxTabCounter--;
1923 }
1924 
1925 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y)
1926 {
1927  ImGuiContext& g = *GImGui;
1928  ImVec2 content_max;
1929  if (size.x < 0.0f || size.y < 0.0f)
1930  content_max = g.CurrentWindow->Pos + GetContentRegionMax();
1931  if (size.x <= 0.0f)
1932  size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x;
1933  if (size.y <= 0.0f)
1934  size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y;
1935  return size;
1936 }
1937 
1938 float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
1939 {
1940  if (wrap_pos_x < 0.0f)
1941  return 0.0f;
1942 
1944  if (wrap_pos_x == 0.0f)
1945  wrap_pos_x = GetContentRegionMax().x + window->Pos.x;
1946  else if (wrap_pos_x > 0.0f)
1947  wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
1948 
1949  const float wrap_width = wrap_pos_x > 0.0f ? ImMax(wrap_pos_x - pos.x, 0.00001f) : 0.0f;
1950  return wrap_width;
1951 }
1952 
1953 //-----------------------------------------------------------------------------
1954 
1955 void* ImGui::MemAlloc(size_t sz)
1956 {
1957  GImGui->IO.MetricsAllocs++;
1958  return GImGui->IO.MemAllocFn(sz);
1959 }
1960 
1961 void ImGui::MemFree(void* ptr)
1962 {
1963  if (ptr) GImGui->IO.MetricsAllocs--;
1964  return GImGui->IO.MemFreeFn(ptr);
1965 }
1966 
1968 {
1969  return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn() : "";
1970 }
1971 
1972 void ImGui::SetClipboardText(const char* text)
1973 {
1974  if (GImGui->IO.SetClipboardTextFn)
1975  GImGui->IO.SetClipboardTextFn(text);
1976 }
1977 
1978 const char* ImGui::GetVersion()
1979 {
1980  return IMGUI_VERSION;
1981 }
1982 
1983 // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
1984 // 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
1986 {
1987  return GImGui;
1988 }
1989 
1991 {
1992  GImGui = ctx;
1993 }
1994 
1995 ImGuiContext* ImGui::CreateContext(void* (*malloc_fn)(size_t), void (*free_fn)(void*))
1996 {
1997  if (!malloc_fn) malloc_fn = malloc;
1998  ImGuiContext* ctx = (ImGuiContext*)malloc_fn(sizeof(ImGuiContext));
1999  IM_PLACEMENT_NEW(ctx) ImGuiContext();
2000  ctx->IO.MemAllocFn = malloc_fn;
2001  ctx->IO.MemFreeFn = free_fn ? free_fn : free;
2002  return ctx;
2003 }
2004 
2006 {
2007  void (*free_fn)(void*) = ctx->IO.MemFreeFn;
2008  ctx->~ImGuiContext();
2009  free_fn(ctx);
2010  if (GImGui == ctx)
2011  GImGui = NULL;
2012 }
2013 
2015 {
2016  return GImGui->IO;
2017 }
2018 
2020 {
2021  return GImGui->Style;
2022 }
2023 
2024 // Same value as passed to your RenderDrawListsFn() function. valid after Render() and until the next call to NewFrame()
2026 {
2027  return GImGui->RenderDrawData.Valid ? &GImGui->RenderDrawData : NULL;
2028 }
2029 
2031 {
2032  return GImGui->Time;
2033 }
2034 
2036 {
2037  return GImGui->FrameCount;
2038 }
2039 
2041 {
2042  ImGuiContext& g = *GImGui;
2043 
2044  if (g.IO.DeltaTime < 0.0f) g.IO.DeltaTime = 0.0f;
2045 
2046  // Check user data
2047  IM_ASSERT(g.IO.DeltaTime >= 0.0f); // Need a positive DeltaTime (zero is tolerated but will cause some timing issues)
2048  IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f);
2049  IM_ASSERT(g.IO.Fonts->Fonts.Size > 0); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
2050  IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
2051  IM_ASSERT(g.Style.CurveTessellationTol > 0.0f); // Invalid style setting
2052 
2053  if (!g.Initialized)
2054  {
2055  // Initialize on first frame
2057  IM_PLACEMENT_NEW(g.LogClipboard) ImGuiTextBuffer();
2058 
2059  IM_ASSERT(g.Settings.empty());
2060  LoadSettings();
2061  g.Initialized = true;
2062  }
2063 
2064  SetCurrentFont(g.IO.Fonts->Fonts[0]);
2065 
2066  g.Time += g.IO.DeltaTime;
2067  g.FrameCount += 1;
2068  g.Tooltip[0] = '\0';
2069  g.OverlayDrawList.Clear();
2073 
2074  // Mark rendering data as invalid to prevent user who may have a handle on it to use it
2075  g.RenderDrawData.Valid = false;
2078 
2079  // Update inputs state
2080  if (g.IO.MousePos.x < 0 && g.IO.MousePos.y < 0)
2081  g.IO.MousePos = ImVec2(-9999.0f, -9999.0f);
2082  if ((g.IO.MousePos.x < 0 && g.IO.MousePos.y < 0) || (g.IO.MousePosPrev.x < 0 && g.IO.MousePosPrev.y < 0)) // if mouse just appeared or disappeared (negative coordinate) we cancel out movement in MouseDelta
2083  g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
2084  else
2085  g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
2086  g.IO.MousePosPrev = g.IO.MousePos;
2087  for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
2088  {
2089  g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
2090  g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
2092  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;
2093  g.IO.MouseDoubleClicked[i] = false;
2094  if (g.IO.MouseClicked[i])
2095  {
2097  {
2099  g.IO.MouseDoubleClicked[i] = true;
2100  g.IO.MouseClickedTime[i] = -FLT_MAX; // so the third click isn't turned into a double-click
2101  }
2102  else
2103  {
2104  g.IO.MouseClickedTime[i] = g.Time;
2105  }
2106  g.IO.MouseClickedPos[i] = g.IO.MousePos;
2107  g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
2108  }
2109  else if (g.IO.MouseDown[i])
2110  {
2112  }
2113  }
2115  for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
2116  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;
2117 
2118  // Calculate frame-rate for the user, as a purely luxurious feature
2123 
2124  // Clear reference to active widget if the widget isn't alive anymore
2126  g.HoveredId = 0;
2127  g.HoveredIdAllowOverlap = false;
2128  if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
2129  SetActiveID(0);
2131  g.ActiveIdIsAlive = false;
2132  g.ActiveIdIsJustActivated = false;
2133 
2134  // Handle user moving window (at the beginning of the frame to avoid input lag or sheering). Only valid for root windows.
2136  {
2140  if (g.IO.MouseDown[0])
2141  {
2143  {
2147  }
2149  }
2150  else
2151  {
2152  SetActiveID(0);
2153  g.MovedWindow = NULL;
2154  g.MovedWindowMoveId = 0;
2155  }
2156  }
2157  else
2158  {
2159  g.MovedWindow = NULL;
2160  g.MovedWindowMoveId = 0;
2161  }
2162 
2163  // Delay saving settings so we don't spam disk too much
2164  if (g.SettingsDirtyTimer > 0.0f)
2165  {
2167  if (g.SettingsDirtyTimer <= 0.0f)
2168  SaveSettings();
2169  }
2170 
2171  // Find the window we are hovering. Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow
2175  else
2177 
2178  if (ImGuiWindow* modal_window = GetFrontMostModalRootWindow())
2179  {
2182  while (window && window != modal_window)
2183  window = window->ParentWindow;
2184  if (!window)
2186  }
2187  else
2188  {
2189  g.ModalWindowDarkeningRatio = 0.0f;
2190  }
2191 
2192  // Are we using inputs? Tell user so they can capture/discard the inputs away from the rest of their application.
2193  // 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.
2194  int mouse_earliest_button_down = -1;
2195  bool mouse_any_down = false;
2196  for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
2197  {
2198  if (g.IO.MouseClicked[i])
2199  g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty());
2200  mouse_any_down |= g.IO.MouseDown[i];
2201  if (g.IO.MouseDown[i])
2202  if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[mouse_earliest_button_down] > g.IO.MouseClickedTime[i])
2203  mouse_earliest_button_down = i;
2204  }
2205  bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
2206  if (g.CaptureMouseNextFrame != -1)
2208  else
2209  g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.ActiveId != 0) || (!g.OpenPopupStack.empty());
2211  g.IO.WantTextInput = (g.ActiveId != 0 && g.InputTextState.Id == g.ActiveId);
2214  g.OsImePosRequest = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
2215 
2216  // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
2217  if (!mouse_avail_to_imgui)
2219 
2220  // Scale & Scrolling
2221  if (g.HoveredWindow && g.IO.MouseWheel != 0.0f && !g.HoveredWindow->Collapsed)
2222  {
2224  if (g.IO.KeyCtrl)
2225  {
2226  if (g.IO.FontAllowUserScaling)
2227  {
2228  // Zoom / Scale window
2229  float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
2230  float scale = new_font_scale / window->FontWindowScale;
2231  window->FontWindowScale = new_font_scale;
2232 
2233  const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
2234  window->Pos += offset;
2235  window->PosFloat += offset;
2236  window->Size *= scale;
2237  window->SizeFull *= scale;
2238  }
2239  }
2240  else
2241  {
2242  // Scroll
2243  if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse))
2244  {
2245  const int scroll_lines = (window->Flags & ImGuiWindowFlags_ComboBox) ? 3 : 5;
2246  SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * window->CalcFontSize() * scroll_lines);
2247  }
2248  }
2249  }
2250 
2251  // Pressing TAB activate widget focus
2252  // 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.
2253  if (g.ActiveId == 0 && g.FocusedWindow != NULL && g.FocusedWindow->Active && IsKeyPressedMap(ImGuiKey_Tab, false))
2255 
2256  // Mark all windows as not visible
2257  for (int i = 0; i != g.Windows.Size; i++)
2258  {
2259  ImGuiWindow* window = g.Windows[i];
2260  window->WasActive = window->Active;
2261  window->Active = false;
2262  window->Accessed = false;
2263  }
2264 
2265  // No window should be open at the beginning of the frame.
2266  // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
2270 
2271  // Create implicit window - we will only render it if the user has added something to it.
2273  ImGui::Begin("Debug");
2274 }
2275 
2276 // NB: behavior of ImGui after Shutdown() is not tested/guaranteed at the moment. This function is merely here to free heap allocations.
2278 {
2279  ImGuiContext& g = *GImGui;
2280 
2281  // 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)
2282  if (g.IO.Fonts) // Testing for NULL to allow user to NULLify in case of running Shutdown() on multiple contexts. Bit hacky.
2283  g.IO.Fonts->Clear();
2284 
2285  // Cleanup of other data are conditional on actually having used ImGui.
2286  if (!g.Initialized)
2287  return;
2288 
2289  SaveSettings();
2290 
2291  for (int i = 0; i < g.Windows.Size; i++)
2292  {
2293  g.Windows[i]->~ImGuiWindow();
2294  ImGui::MemFree(g.Windows[i]);
2295  }
2296  g.Windows.clear();
2299  g.FocusedWindow = NULL;
2300  g.HoveredWindow = NULL;
2301  g.HoveredRootWindow = NULL;
2302  for (int i = 0; i < g.Settings.Size; i++)
2303  ImGui::MemFree(g.Settings[i].Name);
2304  g.Settings.clear();
2305  g.ColorModifiers.clear();
2306  g.StyleModifiers.clear();
2307  g.FontStack.clear();
2308  g.OpenPopupStack.clear();
2310  for (int i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
2311  g.RenderDrawLists[i].clear();
2314  if (g.PrivateClipboard)
2315  {
2317  g.PrivateClipboard = NULL;
2318  }
2322 
2323  if (g.LogFile && g.LogFile != stdout)
2324  {
2325  fclose(g.LogFile);
2326  g.LogFile = NULL;
2327  }
2328  if (g.LogClipboard)
2329  {
2330  g.LogClipboard->~ImGuiTextBuffer();
2332  }
2333 
2334  g.Initialized = false;
2335 }
2336 
2338 {
2339  ImGuiContext& g = *GImGui;
2340  ImGuiID id = ImHash(name, 0);
2341  for (int i = 0; i != g.Settings.Size; i++)
2342  {
2343  ImGuiIniData* ini = &g.Settings[i];
2344  if (ini->ID == id)
2345  return ini;
2346  }
2347  return NULL;
2348 }
2349 
2351 {
2352  GImGui->Settings.resize(GImGui->Settings.Size + 1);
2353  ImGuiIniData* ini = &GImGui->Settings.back();
2354  ini->Name = ImStrdup(name);
2355  ini->ID = ImHash(name, 0);
2356  ini->Collapsed = false;
2357  ini->Pos = ImVec2(FLT_MAX,FLT_MAX);
2358  ini->Size = ImVec2(0,0);
2359  return ini;
2360 }
2361 
2362 // Zero-tolerance, poor-man .ini parsing
2363 // FIXME: Write something less rubbish
2364 static void LoadSettings()
2365 {
2366  ImGuiContext& g = *GImGui;
2367  const char* filename = g.IO.IniFilename;
2368  if (!filename)
2369  return;
2370 
2371  int file_size;
2372  char* file_data = (char*)ImLoadFileToMemory(filename, "rb", &file_size, 1);
2373  if (!file_data)
2374  return;
2375 
2376  ImGuiIniData* settings = NULL;
2377  const char* buf_end = file_data + file_size;
2378  for (const char* line_start = file_data; line_start < buf_end; )
2379  {
2380  const char* line_end = line_start;
2381  while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
2382  line_end++;
2383 
2384  if (line_start[0] == '[' && line_end > line_start && line_end[-1] == ']')
2385  {
2386  char name[64];
2387  ImFormatString(name, IM_ARRAYSIZE(name), "%.*s", (int)(line_end-line_start-2), line_start+1);
2388  settings = FindWindowSettings(name);
2389  if (!settings)
2390  settings = AddWindowSettings(name);
2391  }
2392  else if (settings)
2393  {
2394  float x, y;
2395  int i;
2396  if (sscanf(line_start, "Pos=%f,%f", &x, &y) == 2)
2397  settings->Pos = ImVec2(x, y);
2398  else if (sscanf(line_start, "Size=%f,%f", &x, &y) == 2)
2399  settings->Size = ImMax(ImVec2(x, y), g.Style.WindowMinSize);
2400  else if (sscanf(line_start, "Collapsed=%d", &i) == 1)
2401  settings->Collapsed = (i != 0);
2402  }
2403 
2404  line_start = line_end+1;
2405  }
2406 
2407  ImGui::MemFree(file_data);
2408 }
2409 
2410 static void SaveSettings()
2411 {
2412  ImGuiContext& g = *GImGui;
2413  const char* filename = g.IO.IniFilename;
2414  if (!filename)
2415  return;
2416 
2417  // Gather data from windows that were active during this session
2418  for (int i = 0; i != g.Windows.Size; i++)
2419  {
2420  ImGuiWindow* window = g.Windows[i];
2422  continue;
2423  ImGuiIniData* settings = FindWindowSettings(window->Name);
2424  settings->Pos = window->Pos;
2425  settings->Size = window->SizeFull;
2426  settings->Collapsed = window->Collapsed;
2427  }
2428 
2429  // Write .ini file
2430  // If a window wasn't opened in this session we preserve its settings
2431  FILE* f = fopen(filename, "wt");
2432  if (!f)
2433  return;
2434  for (int i = 0; i != g.Settings.Size; i++)
2435  {
2436  const ImGuiIniData* settings = &g.Settings[i];
2437  if (settings->Pos.x == FLT_MAX)
2438  continue;
2439  const char* name = settings->Name;
2440  if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
2441  name = p;
2442  fprintf(f, "[%s]\n", name);
2443  fprintf(f, "Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
2444  fprintf(f, "Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
2445  fprintf(f, "Collapsed=%d\n", settings->Collapsed);
2446  fprintf(f, "\n");
2447  }
2448 
2449  fclose(f);
2450 }
2451 
2452 static void MarkSettingsDirty()
2453 {
2454  ImGuiContext& g = *GImGui;
2455  if (g.SettingsDirtyTimer <= 0.0f)
2457 }
2458 
2459 // FIXME: Add a more explicit sort order in the window structure.
2460 static int ChildWindowComparer(const void* lhs, const void* rhs)
2461 {
2462  const ImGuiWindow* a = *(const ImGuiWindow**)lhs;
2463  const ImGuiWindow* b = *(const ImGuiWindow**)rhs;
2464  if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
2465  return d;
2467  return d;
2469  return d;
2470  return (a->IndexWithinParent - b->IndexWithinParent);
2471 }
2472 
2474 {
2475  out_sorted_windows.push_back(window);
2476  if (window->Active)
2477  {
2478  int count = window->DC.ChildWindows.Size;
2479  if (count > 1)
2480  qsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
2481  for (int i = 0; i < count; i++)
2482  {
2483  ImGuiWindow* child = window->DC.ChildWindows[i];
2484  if (child->Active)
2485  AddWindowToSortedBuffer(out_sorted_windows, child);
2486  }
2487  }
2488 }
2489 
2490 static void AddDrawListToRenderList(ImVector<ImDrawList*>& out_render_list, ImDrawList* draw_list)
2491 {
2492  if (draw_list->CmdBuffer.empty())
2493  return;
2494 
2495  // Remove trailing command if unused
2496  ImDrawCmd& last_cmd = draw_list->CmdBuffer.back();
2497  if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL)
2498  {
2499  draw_list->CmdBuffer.pop_back();
2500  if (draw_list->CmdBuffer.empty())
2501  return;
2502  }
2503 
2504  // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
2505  IM_ASSERT(draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
2506  IM_ASSERT(draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
2507  IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
2508 
2509  // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = 2 bytes = 64K vertices)
2510  // If this assert triggers because you are drawing lots of stuff manually, A) workaround by calling BeginChild()/EndChild() to put your draw commands in multiple draw lists, B) #define ImDrawIdx to a 'unsigned int' in imconfig.h and render accordingly.
2511  IM_ASSERT((int64_t)draw_list->_VtxCurrentIdx <= ((int64_t)1L << (sizeof(ImDrawIdx)*8))); // Too many vertices in same ImDrawList. See comment above.
2512 
2513  out_render_list.push_back(draw_list);
2514  GImGui->IO.MetricsRenderVertices += draw_list->VtxBuffer.Size;
2515  GImGui->IO.MetricsRenderIndices += draw_list->IdxBuffer.Size;
2516 }
2517 
2519 {
2520  AddDrawListToRenderList(out_render_list, window->DrawList);
2521  for (int i = 0; i < window->DC.ChildWindows.Size; i++)
2522  {
2523  ImGuiWindow* child = window->DC.ChildWindows[i];
2524  if (!child->Active) // clipped children may have been marked not active
2525  continue;
2526  if ((child->Flags & ImGuiWindowFlags_Popup) && child->HiddenFrames > 0)
2527  continue;
2528  AddWindowToRenderList(out_render_list, child);
2529  }
2530 }
2531 
2532 // 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.
2533 void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
2534 {
2536  window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
2537  window->ClipRect = window->DrawList->_ClipRectStack.back();
2538 }
2539 
2541 {
2543  window->DrawList->PopClipRect();
2544  window->ClipRect = window->DrawList->_ClipRectStack.back();
2545 }
2546 
2547 // 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.
2549 {
2550  ImGuiContext& g = *GImGui;
2551  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
2552  IM_ASSERT(g.FrameCountEnded != g.FrameCount); // ImGui::EndFrame() called multiple times, or forgot to call ImGui::NewFrame() again
2553 
2554  // Render tooltip
2555  if (g.Tooltip[0])
2556  {
2560  }
2561 
2562  // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
2564  {
2567  }
2568 
2569  // Hide implicit "Debug" window if it hasn't been used
2570  IM_ASSERT(g.CurrentWindowStack.Size == 1); // Mismatched Begin()/End() calls
2571  if (g.CurrentWindow && !g.CurrentWindow->Accessed)
2572  g.CurrentWindow->Active = false;
2573  ImGui::End();
2574 
2575  // Click to focus window and start moving (after we're done with all our widgets)
2576  if (g.ActiveId == 0 && g.HoveredId == 0 && g.IO.MouseClicked[0])
2577  {
2578  if (!(g.FocusedWindow && !g.FocusedWindow->WasActive && g.FocusedWindow->Active)) // Unless we just made a popup appear
2579  {
2580  if (g.HoveredRootWindow != NULL)
2581  {
2584  {
2585  g.MovedWindow = g.HoveredWindow;
2588  }
2589  }
2590  else if (g.FocusedWindow != NULL && GetFrontMostModalRootWindow() == NULL)
2591  {
2592  // Clicking on void disable focus
2593  FocusWindow(NULL);
2594  }
2595  }
2596  }
2597 
2598  // Sort the window list so that all child windows are after their parent
2599  // We cannot do that on FocusWindow() because childs may not exist yet
2602  for (int i = 0; i != g.Windows.Size; i++)
2603  {
2604  ImGuiWindow* window = g.Windows[i];
2605  if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it
2606  continue;
2608  }
2609  IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size); // we done something wrong
2611 
2612  // Clear Input data for next frame
2613  g.IO.MouseWheel = 0.0f;
2614  memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
2615 
2617 }
2618 
2620 {
2621  ImGuiContext& g = *GImGui;
2622  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
2623 
2624  if (g.FrameCountEnded != g.FrameCount)
2625  ImGui::EndFrame();
2627 
2628  // Skip render altogether if alpha is 0.0
2629  // 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.
2630  if (g.Style.Alpha > 0.0f)
2631  {
2632  // Gather windows to render
2634  for (int i = 0; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
2635  g.RenderDrawLists[i].resize(0);
2636  for (int i = 0; i != g.Windows.Size; i++)
2637  {
2638  ImGuiWindow* window = g.Windows[i];
2639  if (window->Active && window->HiddenFrames <= 0 && (window->Flags & (ImGuiWindowFlags_ChildWindow)) == 0)
2640  {
2641  // FIXME: Generalize this with a proper layering system so e.g. user can draw in specific layers, below text, ..
2643  if (window->Flags & ImGuiWindowFlags_Popup)
2644  AddWindowToRenderList(g.RenderDrawLists[1], window);
2645  else if (window->Flags & ImGuiWindowFlags_Tooltip)
2646  AddWindowToRenderList(g.RenderDrawLists[2], window);
2647  else
2648  AddWindowToRenderList(g.RenderDrawLists[0], window);
2649  }
2650  }
2651 
2652  // Flatten layers
2653  int n = g.RenderDrawLists[0].Size;
2654  int flattened_size = n;
2655  for (int i = 1; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
2656  flattened_size += g.RenderDrawLists[i].Size;
2657  g.RenderDrawLists[0].resize(flattened_size);
2658  for (int i = 1; i < IM_ARRAYSIZE(g.RenderDrawLists); i++)
2659  {
2661  if (layer.empty())
2662  continue;
2663  memcpy(&g.RenderDrawLists[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
2664  n += layer.Size;
2665  }
2666 
2667  // Draw software mouse cursor if requested
2668  if (g.IO.MouseDrawCursor)
2669  {
2670  const ImGuiMouseCursorData& cursor_data = g.MouseCursorData[g.MouseCursor];
2671  const ImVec2 pos = g.IO.MousePos - cursor_data.HotOffset;
2672  const ImVec2 size = cursor_data.Size;
2673  const ImTextureID tex_id = g.IO.Fonts->TexID;
2674  g.OverlayDrawList.PushTextureID(tex_id);
2675  g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(1,0), pos+ImVec2(1,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow
2676  g.OverlayDrawList.AddImage(tex_id, pos+ImVec2(2,0), pos+ImVec2(2,0) + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0x30000000); // Shadow
2677  g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[1], cursor_data.TexUvMax[1], 0xFF000000); // Black border
2678  g.OverlayDrawList.AddImage(tex_id, pos, pos + size, cursor_data.TexUvMin[0], cursor_data.TexUvMax[0], 0xFFFFFFFF); // White fill
2680  }
2681  if (!g.OverlayDrawList.VtxBuffer.empty())
2683 
2684  // Setup draw data
2685  g.RenderDrawData.Valid = true;
2686  g.RenderDrawData.CmdLists = (g.RenderDrawLists[0].Size > 0) ? &g.RenderDrawLists[0][0] : NULL;
2690 
2691  // Render. If user hasn't set a callback then they may retrieve the draw data via GetDrawData()
2694  }
2695 }
2696 
2697 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
2698 {
2699  const char* text_display_end = text;
2700  if (!text_end)
2701  text_end = (const char*)-1;
2702 
2703  while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
2704  text_display_end++;
2705  return text_display_end;
2706 }
2707 
2708 // Pass text data straight to log (without being displayed)
2709 void ImGui::LogText(const char* fmt, ...)
2710 {
2711  ImGuiContext& g = *GImGui;
2712  if (!g.LogEnabled)
2713  return;
2714 
2715  va_list args;
2716  va_start(args, fmt);
2717  if (g.LogFile)
2718  {
2719  vfprintf(g.LogFile, fmt, args);
2720  }
2721  else
2722  {
2723  g.LogClipboard->appendv(fmt, args);
2724  }
2725  va_end(args);
2726 }
2727 
2728 // Internal version that takes a position to decide on newline placement and pad items according to their depth.
2729 // We split text into individual lines to add current tree level padding
2730 static void LogRenderedText(const ImVec2& ref_pos, const char* text, const char* text_end)
2731 {
2732  ImGuiContext& g = *GImGui;
2734 
2735  if (!text_end)
2736  text_end = ImGui::FindRenderedTextEnd(text, text_end);
2737 
2738  const bool log_new_line = ref_pos.y > window->DC.LogLinePosY+1;
2739  window->DC.LogLinePosY = ref_pos.y;
2740 
2741  const char* text_remaining = text;
2742  if (g.LogStartDepth > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth
2743  g.LogStartDepth = window->DC.TreeDepth;
2744  const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth);
2745  for (;;)
2746  {
2747  // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
2748  const char* line_end = text_remaining;
2749  while (line_end < text_end)
2750  if (*line_end == '\n')
2751  break;
2752  else
2753  line_end++;
2754  if (line_end >= text_end)
2755  line_end = NULL;
2756 
2757  const bool is_first_line = (text == text_remaining);
2758  bool is_last_line = false;
2759  if (line_end == NULL)
2760  {
2761  is_last_line = true;
2762  line_end = text_end;
2763  }
2764  if (line_end != NULL && !(is_last_line && (line_end - text_remaining)==0))
2765  {
2766  const int char_count = (int)(line_end - text_remaining);
2767  if (log_new_line || !is_first_line)
2768  ImGui::LogText(IM_NEWLINE "%*s%.*s", tree_depth*4, "", char_count, text_remaining);
2769  else
2770  ImGui::LogText(" %.*s", char_count, text_remaining);
2771  }
2772 
2773  if (is_last_line)
2774  break;
2775  text_remaining = line_end + 1;
2776  }
2777 }
2778 
2779 // Internal ImGui functions to render text
2780 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
2781 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
2782 {
2783  ImGuiContext& g = *GImGui;
2785 
2786  // Hide anything after a '##' string
2787  const char* text_display_end;
2788  if (hide_text_after_hash)
2789  {
2790  text_display_end = FindRenderedTextEnd(text, text_end);
2791  }
2792  else
2793  {
2794  if (!text_end)
2795  text_end = text + strlen(text); // FIXME-OPT
2796  text_display_end = text_end;
2797  }
2798 
2799  const int text_len = (int)(text_display_end - text);
2800  if (text_len > 0)
2801  {
2802  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
2803  if (g.LogEnabled)
2804  LogRenderedText(pos, text, text_display_end);
2805  }
2806 }
2807 
2808 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
2809 {
2810  ImGuiContext& g = *GImGui;
2812 
2813  if (!text_end)
2814  text_end = text + strlen(text); // FIXME-OPT
2815 
2816  const int text_len = (int)(text_end - text);
2817  if (text_len > 0)
2818  {
2819  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
2820  if (g.LogEnabled)
2821  LogRenderedText(pos, text, text_end);
2822  }
2823 }
2824 
2825 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
2826 void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, ImGuiAlign align, const ImVec2* clip_min, const ImVec2* clip_max)
2827 {
2828  // Hide anything after a '##' string
2829  const char* text_display_end = FindRenderedTextEnd(text, text_end);
2830  const int text_len = (int)(text_display_end - text);
2831  if (text_len == 0)
2832  return;
2833 
2834  ImGuiContext& g = *GImGui;
2836 
2837  // Perform CPU side clipping for single clipped element to avoid using scissor state
2838  ImVec2 pos = pos_min;
2839  const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
2840 
2841  if (!clip_max) clip_max = &pos_max;
2842  bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
2843  if (!clip_min) clip_min = &pos_min; else need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
2844 
2845  // Align
2846  if (align & ImGuiAlign_Center) pos.x = ImMax(pos.x, (pos.x + pos_max.x - text_size.x) * 0.5f);
2847  else if (align & ImGuiAlign_Right) pos.x = ImMax(pos.x, pos_max.x - text_size.x);
2848  if (align & ImGuiAlign_VCenter) pos.y = ImMax(pos.y, (pos.y + pos_max.y - text_size.y) * 0.5f);
2849 
2850  // Render
2851  if (need_clipping)
2852  {
2853  ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
2854  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
2855  }
2856  else
2857  {
2858  window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
2859  }
2860  if (g.LogEnabled)
2861  LogRenderedText(pos, text, text_display_end);
2862 }
2863 
2864 // Render a rectangle shaped with optional rounding and borders
2865 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
2866 {
2868 
2869  window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
2870  if (border && (window->Flags & ImGuiWindowFlags_ShowBorders))
2871  {
2872  window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding);
2873  window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding);
2874  }
2875 }
2876 
2877 // Render a triangle to denote expanded/collapsed state
2878 void ImGui::RenderCollapseTriangle(ImVec2 p_min, bool is_open, float scale, bool shadow)
2879 {
2880  ImGuiContext& g = *GImGui;
2882 
2883  const float h = g.FontSize * 1.00f;
2884  const float r = h * 0.40f * scale;
2885  ImVec2 center = p_min + ImVec2(h*0.50f, h*0.50f*scale);
2886 
2887  ImVec2 a, b, c;
2888  if (is_open)
2889  {
2890  center.y -= r*0.25f;
2891  a = center + ImVec2(0,1)*r;
2892  b = center + ImVec2(-0.866f,-0.5f)*r;
2893  c = center + ImVec2(0.866f,-0.5f)*r;
2894  }
2895  else
2896  {
2897  a = center + ImVec2(1,0)*r;
2898  b = center + ImVec2(-0.500f,0.866f)*r;
2899  c = center + ImVec2(-0.500f,-0.866f)*r;
2900  }
2901 
2902  if (shadow && (window->Flags & ImGuiWindowFlags_ShowBorders) != 0)
2903  window->DrawList->AddTriangleFilled(a+ImVec2(2,2), b+ImVec2(2,2), c+ImVec2(2,2), GetColorU32(ImGuiCol_BorderShadow));
2905 }
2906 
2908 {
2910  window->DrawList->AddCircleFilled(pos, GImGui->FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8);
2911 }
2912 
2914 {
2915  ImGuiContext& g = *GImGui;
2917 
2918  ImVec2 a, b, c;
2919  float start_x = (float)(int)(g.FontSize * 0.307f + 0.5f);
2920  float rem_third = (float)(int)((g.FontSize - start_x) / 3.0f);
2921  a.x = pos.x + 0.5f + start_x;
2922  b.x = a.x + rem_third;
2923  c.x = a.x + rem_third * 3.0f;
2924  b.y = pos.y - 1.0f + (float)(int)(g.Font->Ascent * (g.FontSize / g.Font->FontSize) + 0.5f) + (float)(int)(g.Font->DisplayOffset.y);
2925  a.y = b.y - rem_third;
2926  c.y = b.y - rem_third * 2.0f;
2927 
2928  window->DrawList->PathLineTo(a);
2929  window->DrawList->PathLineTo(b);
2930  window->DrawList->PathLineTo(c);
2931  window->DrawList->PathStroke(col, false);
2932 }
2933 
2934 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
2935 // CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize)
2936 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
2937 {
2938  ImGuiContext& g = *GImGui;
2939 
2940  const char* text_display_end;
2941  if (hide_text_after_double_hash)
2942  text_display_end = FindRenderedTextEnd(text, text_end); // Hide anything after a '##' string
2943  else
2944  text_display_end = text_end;
2945 
2946  ImFont* font = g.Font;
2947  const float font_size = g.FontSize;
2948  if (text == text_display_end)
2949  return ImVec2(0.0f, font_size);
2950  ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
2951 
2952  // Cancel out character spacing for the last character of a line (it is baked into glyph->XAdvance field)
2953  const float font_scale = font_size / font->FontSize;
2954  const float character_spacing_x = 1.0f * font_scale;
2955  if (text_size.x > 0.0f)
2956  text_size.x -= character_spacing_x;
2957  text_size.x = (float)(int)(text_size.x + 0.95f);
2958 
2959  return text_size;
2960 }
2961 
2962 // Helper to calculate coarse clipping of large list of evenly sized items.
2963 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
2964 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
2965 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
2966 {
2967  ImGuiContext& g = *GImGui;
2969  if (g.LogEnabled)
2970  {
2971  // If logging is active, do not perform any clipping
2972  *out_items_display_start = 0;
2973  *out_items_display_end = items_count;
2974  return;
2975  }
2976  if (window->SkipItems)
2977  {
2978  *out_items_display_start = *out_items_display_end = 0;
2979  return;
2980  }
2981 
2982  const ImVec2 pos = window->DC.CursorPos;
2983  int start = (int)((window->ClipRect.Min.y - pos.y) / items_height);
2984  int end = (int)((window->ClipRect.Max.y - pos.y) / items_height);
2985  start = ImClamp(start, 0, items_count);
2986  end = ImClamp(end + 1, start, items_count);
2987  *out_items_display_start = start;
2988  *out_items_display_end = end;
2989 }
2990 
2991 // Find window given position, search front-to-back
2992 // 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.
2993 static ImGuiWindow* FindHoveredWindow(ImVec2 pos, bool excluding_childs)
2994 {
2995  ImGuiContext& g = *GImGui;
2996  for (int i = g.Windows.Size-1; i >= 0; i--)
2997  {
2998  ImGuiWindow* window = g.Windows[i];
2999  if (!window->Active)
3000  continue;
3001  if (window->Flags & ImGuiWindowFlags_NoInputs)
3002  continue;
3003  if (excluding_childs && (window->Flags & ImGuiWindowFlags_ChildWindow) != 0)
3004  continue;
3005 
3006  // Using the clipped AABB so a child window will typically be clipped by its parent.
3008  if (bb.Contains(pos))
3009  return window;
3010  }
3011  return NULL;
3012 }
3013 
3014 // Test if mouse cursor is hovering given rectangle
3015 // NB- Rectangle is clipped by our current clip setting
3016 // NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
3017 bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
3018 {
3019  ImGuiContext& g = *GImGui;
3021 
3022  // Clip
3023  ImRect rect_clipped(r_min, r_max);
3024  if (clip)
3025  rect_clipped.Clip(window->ClipRect);
3026 
3027  // Expand for touch input
3028  const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
3029  return rect_for_touch.Contains(g.IO.MousePos);
3030 }
3031 
3033 {
3034  ImGuiContext& g = *GImGui;
3035  return g.HoveredWindow == g.CurrentWindow;
3036 }
3037 
3039 {
3040  ImGuiContext& g = *GImGui;
3041  return g.HoveredWindow != NULL;
3042 }
3043 
3045 {
3046  return FindHoveredWindow(pos, false) != NULL;
3047 }
3048 
3050 {
3051  const int key_index = GImGui->IO.KeyMap[key];
3052  return ImGui::IsKeyPressed(key_index, repeat);
3053 }
3054 
3056 {
3057  IM_ASSERT(key >= 0 && key < ImGuiKey_COUNT);
3058  return GImGui->IO.KeyMap[key];
3059 }
3060 
3061 bool ImGui::IsKeyDown(int key_index)
3062 {
3063  if (key_index < 0) return false;
3064  IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown));
3065  return GImGui->IO.KeysDown[key_index];
3066 }
3067 
3068 bool ImGui::IsKeyPressed(int key_index, bool repeat)
3069 {
3070  ImGuiContext& g = *GImGui;
3071  if (key_index < 0) return false;
3072  IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
3073  const float t = g.IO.KeysDownDuration[key_index];
3074  if (t == 0.0f)
3075  return true;
3076 
3077  if (repeat && t > g.IO.KeyRepeatDelay)
3078  {
3079  float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate;
3080  if ((fmodf(t - delay, rate) > rate*0.5f) != (fmodf(t - delay - g.IO.DeltaTime, rate) > rate*0.5f))
3081  return true;
3082  }
3083  return false;
3084 }
3085 
3086 bool ImGui::IsKeyReleased(int key_index)
3087 {
3088  ImGuiContext& g = *GImGui;
3089  if (key_index < 0) return false;
3090  IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
3091  if (g.IO.KeysDownDurationPrev[key_index] >= 0.0f && !g.IO.KeysDown[key_index])
3092  return true;
3093  return false;
3094 }
3095 
3096 bool ImGui::IsMouseDown(int button)
3097 {
3098  ImGuiContext& g = *GImGui;
3099  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3100  return g.IO.MouseDown[button];
3101 }
3102 
3103 bool ImGui::IsMouseClicked(int button, bool repeat)
3104 {
3105  ImGuiContext& g = *GImGui;
3106  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3107  const float t = g.IO.MouseDownDuration[button];
3108  if (t == 0.0f)
3109  return true;
3110 
3111  if (repeat && t > g.IO.KeyRepeatDelay)
3112  {
3113  float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate;
3114  if ((fmodf(t - delay, rate) > rate*0.5f) != (fmodf(t - delay - g.IO.DeltaTime, rate) > rate*0.5f))
3115  return true;
3116  }
3117 
3118  return false;
3119 }
3120 
3121 bool ImGui::IsMouseReleased(int button)
3122 {
3123  ImGuiContext& g = *GImGui;
3124  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3125  return g.IO.MouseReleased[button];
3126 }
3127 
3129 {
3130  ImGuiContext& g = *GImGui;
3131  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3132  return g.IO.MouseDoubleClicked[button];
3133 }
3134 
3135 bool ImGui::IsMouseDragging(int button, float lock_threshold)
3136 {
3137  ImGuiContext& g = *GImGui;
3138  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3139  if (!g.IO.MouseDown[button])
3140  return false;
3141  if (lock_threshold < 0.0f)
3142  lock_threshold = g.IO.MouseDragThreshold;
3143  return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
3144 }
3145 
3147 {
3148  return GImGui->IO.MousePos;
3149 }
3150 
3151 // NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
3153 {
3154  ImGuiContext& g = *GImGui;
3155  if (g.CurrentPopupStack.Size > 0)
3156  return g.OpenPopupStack[g.CurrentPopupStack.Size-1].MousePosOnOpen;
3157  return g.IO.MousePos;
3158 }
3159 
3160 ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
3161 {
3162  ImGuiContext& g = *GImGui;
3163  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3164  if (lock_threshold < 0.0f)
3165  lock_threshold = g.IO.MouseDragThreshold;
3166  if (g.IO.MouseDown[button])
3167  if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
3168  return g.IO.MousePos - g.IO.MouseClickedPos[button]; // Assume we can only get active with left-mouse button (at the moment).
3169  return ImVec2(0.0f, 0.0f);
3170 }
3171 
3173 {
3174  ImGuiContext& g = *GImGui;
3175  IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
3176  // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
3177  g.IO.MouseClickedPos[button] = g.IO.MousePos;
3178 }
3179 
3181 {
3182  return GImGui->MouseCursor;
3183 }
3184 
3186 {
3187  GImGui->MouseCursor = cursor_type;
3188 }
3189 
3191 {
3192  GImGui->CaptureKeyboardNextFrame = capture ? 1 : 0;
3193 }
3194 
3195 void ImGui::CaptureMouseFromApp(bool capture)
3196 {
3197  GImGui->CaptureMouseNextFrame = capture ? 1 : 0;
3198 }
3199 
3201 {
3203  return window->DC.LastItemHoveredAndUsable;
3204 }
3205 
3207 {
3209  return window->DC.LastItemHoveredRect;
3210 }
3211 
3213 {
3214  ImGuiContext& g = *GImGui;
3215  if (g.ActiveId)
3216  {
3218  return g.ActiveId == window->DC.LastItemID;
3219  }
3220  return false;
3221 }
3222 
3223 bool ImGui::IsItemClicked(int mouse_button)
3224 {
3225  return IsMouseClicked(mouse_button) && IsItemHovered();
3226 }
3227 
3229 {
3230  return GImGui->HoveredId != 0 || GImGui->HoveredIdPreviousFrame != 0;
3231 }
3232 
3234 {
3235  return GImGui->ActiveId != 0;
3236 }
3237 
3239 {
3241  ImRect r(window->ClipRect);
3242  return r.Overlaps(window->DC.LastItemRect);
3243 }
3244 
3245 // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
3247 {
3248  ImGuiContext& g = *GImGui;
3249  if (g.HoveredId == g.CurrentWindow->DC.LastItemID)
3250  g.HoveredIdAllowOverlap = true;
3251  if (g.ActiveId == g.CurrentWindow->DC.LastItemID)
3252  g.ActiveIdAllowOverlap = true;
3253 }
3254 
3256 {
3258  return window->DC.LastItemRect.Min;
3259 }
3260 
3262 {
3264  return window->DC.LastItemRect.Max;
3265 }
3266 
3268 {
3270  return window->DC.LastItemRect.GetSize();
3271 }
3272 
3273 ImVec2 ImGui::CalcItemRectClosestPoint(const ImVec2& pos, bool on_edge, float outward)
3274 {
3276  ImRect rect = window->DC.LastItemRect;
3277  rect.Expand(outward);
3278  return rect.GetClosestPoint(pos, on_edge);
3279 }
3280 
3281 // Tooltip is stored and turned into a BeginTooltip()/EndTooltip() sequence at the end of the frame. Each call override previous value.
3282 void ImGui::SetTooltipV(const char* fmt, va_list args)
3283 {
3284  ImGuiContext& g = *GImGui;
3285  ImFormatStringV(g.Tooltip, IM_ARRAYSIZE(g.Tooltip), fmt, args);
3286 }
3287 
3288 void ImGui::SetTooltip(const char* fmt, ...)
3289 {
3290  va_list args;
3291  va_start(args, fmt);
3292  SetTooltipV(fmt, args);
3293  va_end(args);
3294 }
3295 
3297 {
3298  ImGuiContext& g = *GImGui;
3301  return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
3302 }
3303 
3305 {
3307  ImGui::Begin("##Tooltip", NULL, flags);
3308 }
3309 
3311 {
3312  IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip); // Mismatched BeginTooltip()/EndTooltip() calls
3313  ImGui::End();
3314 }
3315 
3316 static bool IsPopupOpen(ImGuiID id)
3317 {
3318  ImGuiContext& g = *GImGui;
3319  const bool is_open = g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupID == id;
3320  return is_open;
3321 }
3322 
3323 // Mark popup as open (toggle toward open state).
3324 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
3325 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
3326 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
3327 void ImGui::OpenPopupEx(const char* str_id, bool reopen_existing)
3328 {
3329  ImGuiContext& g = *GImGui;
3331  ImGuiID id = window->GetID(str_id);
3332  int current_stack_size = g.CurrentPopupStack.Size;
3333  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)
3334  if (g.OpenPopupStack.Size < current_stack_size + 1)
3335  g.OpenPopupStack.push_back(popup_ref);
3336  else if (reopen_existing || g.OpenPopupStack[current_stack_size].PopupID != id)
3337  {
3338  g.OpenPopupStack.resize(current_stack_size+1);
3339  g.OpenPopupStack[current_stack_size] = popup_ref;
3340  }
3341 }
3342 
3343 void ImGui::OpenPopup(const char* str_id)
3344 {
3345  ImGui::OpenPopupEx(str_id, false);
3346 }
3347 
3348 static void CloseInactivePopups()
3349 {
3350  ImGuiContext& g = *GImGui;
3351  if (g.OpenPopupStack.empty())
3352  return;
3353 
3354  // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
3355  // Don't close our own child popup windows
3356  int n = 0;
3357  if (g.FocusedWindow)
3358  {
3359  for (n = 0; n < g.OpenPopupStack.Size; n++)
3360  {
3361  ImGuiPopupRef& popup = g.OpenPopupStack[n];
3362  if (!popup.Window)
3363  continue;
3364  IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
3366  continue;
3367 
3368  bool has_focus = false;
3369  for (int m = n; m < g.OpenPopupStack.Size && !has_focus; m++)
3370  has_focus = (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == g.FocusedWindow->RootWindow);
3371  if (!has_focus)
3372  break;
3373  }
3374  }
3375  if (n < g.OpenPopupStack.Size) // This test is not required but it allows to set a useful breakpoint on the line below
3376  g.OpenPopupStack.resize(n);
3377 }
3378 
3380 {
3381  ImGuiContext& g = *GImGui;
3382  for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
3383  if (ImGuiWindow* front_most_popup = g.OpenPopupStack.Data[n].Window)
3384  if (front_most_popup->Flags & ImGuiWindowFlags_Modal)
3385  return front_most_popup;
3386  return NULL;
3387 }
3388 
3389 static void ClosePopupToLevel(int remaining)
3390 {
3391  ImGuiContext& g = *GImGui;
3392  if (remaining > 0)
3393  ImGui::FocusWindow(g.OpenPopupStack[remaining-1].Window);
3394  else
3395  ImGui::FocusWindow(g.OpenPopupStack[0].ParentWindow);
3396  g.OpenPopupStack.resize(remaining);
3397 }
3398 
3399 static void ClosePopup(ImGuiID id)
3400 {
3401  if (!IsPopupOpen(id))
3402  return;
3403  ImGuiContext& g = *GImGui;
3405 }
3406 
3407 // Close the popup we have begin-ed into.
3409 {
3410  ImGuiContext& g = *GImGui;
3411  int popup_idx = g.CurrentPopupStack.Size - 1;
3412  if (popup_idx < 0 || popup_idx > g.OpenPopupStack.Size || g.CurrentPopupStack[popup_idx].PopupID != g.OpenPopupStack[popup_idx].PopupID)
3413  return;
3414  while (popup_idx > 0 && g.OpenPopupStack[popup_idx].Window && (g.OpenPopupStack[popup_idx].Window->Flags & ImGuiWindowFlags_ChildMenu))
3415  popup_idx--;
3416  ClosePopupToLevel(popup_idx);
3417 }
3418 
3419 static inline void ClearSetNextWindowData()
3420 {
3421  ImGuiContext& g = *GImGui;
3424 }
3425 
3426 static bool BeginPopupEx(const char* str_id, ImGuiWindowFlags extra_flags)
3427 {
3428  ImGuiContext& g = *GImGui;
3430  const ImGuiID id = window->GetID(str_id);
3431  if (!IsPopupOpen(id))
3432  {
3433  ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
3434  return false;
3435  }
3436 
3439 
3440  char name[32];
3441  if (flags & ImGuiWindowFlags_ChildMenu)
3442  ImFormatString(name, 20, "##menu_%d", g.CurrentPopupStack.Size); // Recycle windows based on depth
3443  else
3444  ImFormatString(name, 20, "##popup_%08x", id); // Not recycling, so we can close/open during the same frame
3445 
3446  bool is_open = ImGui::Begin(name, NULL, flags);
3447  if (!(window->Flags & ImGuiWindowFlags_ShowBorders))
3449  if (!is_open) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
3450  ImGui::EndPopup();
3451 
3452  return is_open;
3453 }
3454 
3455 bool ImGui::BeginPopup(const char* str_id)
3456 {
3457  if (GImGui->OpenPopupStack.Size <= GImGui->CurrentPopupStack.Size) // Early out for performance
3458  {
3459  ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
3460  return false;
3461  }
3463 }
3464 
3465 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags extra_flags)
3466 {
3467  ImGuiContext& g = *GImGui;
3469  const ImGuiID id = window->GetID(name);
3470  if (!IsPopupOpen(id))
3471  {
3472  ClearSetNextWindowData(); // We behave like Begin() and need to consume those values
3473  return false;
3474  }
3475 
3477  bool is_open = ImGui::Begin(name, p_open, flags);
3478  if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
3479  {
3480  ImGui::EndPopup();
3481  if (is_open)
3482  ClosePopup(id);
3483  return false;
3484  }
3485 
3486  return is_open;
3487 }
3488 
3490 {
3492  IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginPopup()/EndPopup() calls
3493  IM_ASSERT(GImGui->CurrentPopupStack.Size > 0);
3494  ImGui::End();
3495  if (!(window->Flags & ImGuiWindowFlags_Modal))
3497 }
3498 
3499 // This is a helper to handle the most simple case of associating one named popup to one given widget.
3500 // 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
3501 // this yourself so you can store data relative to the widget that opened the popup instead of choosing different popup identifiers.
3502 // 2. If you want right-clicking on the same item to reopen the popup at new location, use the same code replacing IsItemHovered() with IsItemHoveredRect()
3503 // and passing true to the OpenPopupEx().
3504 // 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
3505 // the item isn't interactable (because it is blocked by the active popup) may useful in some situation when e.g. large canvas as one item, content of menu
3506 // driven by click position.
3507 bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
3508 {
3509  if (IsItemHovered() && IsMouseClicked(mouse_button))
3510  OpenPopupEx(str_id, false);
3511  return BeginPopup(str_id);
3512 }
3513 
3514 bool ImGui::BeginPopupContextWindow(bool also_over_items, const char* str_id, int mouse_button)
3515 {
3516  if (!str_id) str_id = "window_context_menu";
3517  if (IsMouseHoveringWindow() && IsMouseClicked(mouse_button))
3518  if (also_over_items || !IsAnyItemHovered())
3519  OpenPopupEx(str_id, true);
3520  return BeginPopup(str_id);
3521 }
3522 
3523 bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
3524 {
3525  if (!str_id) str_id = "void_context_menu";
3526  if (!IsMouseHoveringAnyWindow() && IsMouseClicked(mouse_button))
3527  OpenPopupEx(str_id, true);
3528  return BeginPopup(str_id);
3529 }
3530 
3531 bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
3532 {
3535 
3536  const ImVec2 content_avail = GetContentRegionAvail();
3537  ImVec2 size = ImFloor(size_arg);
3538  if (size.x <= 0.0f)
3539  {
3540  if (size.x == 0.0f)
3542  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)
3543  }
3544  if (size.y <= 0.0f)
3545  {
3546  if (size.y == 0.0f)
3548  size.y = ImMax(content_avail.y, 4.0f) - fabsf(size.y);
3549  }
3550  if (border)
3552  flags |= extra_flags;
3553 
3554  char title[256];
3555  ImFormatString(title, IM_ARRAYSIZE(title), "%s.%s", window->Name, str_id);
3556 
3557  bool ret = ImGui::Begin(title, NULL, size, -1.0f, flags);
3558 
3559  if (!(window->Flags & ImGuiWindowFlags_ShowBorders))
3561 
3562  return ret;
3563 }
3564 
3565 bool ImGui::BeginChild(ImGuiID id, const ImVec2& size, bool border, ImGuiWindowFlags extra_flags)
3566 {
3567  char str_id[32];
3568  ImFormatString(str_id, IM_ARRAYSIZE(str_id), "child_%08x", id);
3569  bool ret = ImGui::BeginChild(str_id, size, border, extra_flags);
3570  return ret;
3571 }
3572 
3574 {
3576 
3577  IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow); // Mismatched BeginChild()/EndChild() callss
3578  if ((window->Flags & ImGuiWindowFlags_ComboBox) || window->BeginCount > 1)
3579  {
3580  ImGui::End();
3581  }
3582  else
3583  {
3584  // 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.
3585  ImVec2 sz = GetWindowSize();
3586  if (window->Flags & ImGuiWindowFlags_ChildWindowAutoFitX) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
3587  sz.x = ImMax(4.0f, sz.x);
3589  sz.y = ImMax(4.0f, sz.y);
3590 
3591  ImGui::End();
3592 
3593  window = GetCurrentWindow();
3594  ImRect bb(window->DC.CursorPos, window->DC.CursorPos + sz);
3595  ItemSize(sz);
3596  ItemAdd(bb, NULL);
3597  }
3598 }
3599 
3600 // Helper to create a child window / scrolling region that looks like a normal widget frame.
3602 {
3603  ImGuiContext& g = *GImGui;
3604  const ImGuiStyle& style = g.Style;
3609 }
3610 
3612 {
3613  ImGui::EndChild();
3614  ImGui::PopStyleVar(2);
3616 }
3617 
3618 // Save and compare stack sizes on Begin()/End() to detect usage errors
3619 static void CheckStacksSize(ImGuiWindow* window, bool write)
3620 {
3621  // 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)
3622  ImGuiContext& g = *GImGui;
3623  int* p_backup = &window->DC.StackSizesBackup[0];
3624  { int current = window->IDStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushID/PopID Mismatch!"); p_backup++; } // User forgot PopID()
3625  { int current = window->DC.GroupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!"); p_backup++; } // User forgot EndGroup()
3626  { int current = g.CurrentPopupStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++; }// User forgot EndPopup()/EndMenu()
3627  { int current = g.ColorModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushStyleColor/PopStyleColor Mismatch!"); p_backup++; } // User forgot PopStyleColor()
3628  { int current = g.StyleModifiers.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushStyleVar/PopStyleVar Mismatch!"); p_backup++; } // User forgot PopStyleVar()
3629  { int current = g.FontStack.Size; if (write) *p_backup = current; else IM_ASSERT(*p_backup == current && "PushFont/PopFont Mismatch!"); p_backup++; } // User forgot PopFont()
3630  IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
3631 }
3632 
3633 static ImVec2 FindBestPopupWindowPos(const ImVec2& base_pos, const ImVec2& size, int* last_dir, const ImRect& r_inner)
3634 {
3635  const ImGuiStyle& style = GImGui->Style;
3636 
3637  // Clamp into visible area while not overlapping the cursor. Safety padding is optional if our popup size won't fit without it.
3638  ImVec2 safe_padding = style.DisplaySafeAreaPadding;
3639  ImRect r_outer(GetVisibleRect());
3640  r_outer.Reduce(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));
3641  ImVec2 base_pos_clamped = ImClamp(base_pos, r_outer.Min, r_outer.Max - size);
3642 
3643  for (int n = (*last_dir != -1) ? -1 : 0; n < 4; n++) // Last, Right, down, up, left. (Favor last used direction).
3644  {
3645  const int dir = (n == -1) ? *last_dir : n;
3646  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);
3647  if (rect.GetWidth() < size.x || rect.GetHeight() < size.y)
3648  continue;
3649  *last_dir = dir;
3650  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);
3651  }
3652 
3653  // Fallback, try to keep within display
3654  *last_dir = -1;
3655  ImVec2 pos = base_pos;
3656  pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
3657  pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
3658  return pos;
3659 }
3660 
3662 {
3663  // FIXME-OPT: Store sorted hashes -> pointers so we can do a bissection in a contiguous block
3664  ImGuiContext& g = *GImGui;
3665  ImGuiID id = ImHash(name, 0);
3666  for (int i = 0; i < g.Windows.Size; i++)
3667  if (g.Windows[i]->ID == id)
3668  return g.Windows[i];
3669  return NULL;
3670 }
3671 
3673 {
3674  ImGuiContext& g = *GImGui;
3675 
3676  // Create window the first time
3678  IM_PLACEMENT_NEW(window) ImGuiWindow(name);
3679  window->Flags = flags;
3680 
3682  {
3683  // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
3684  window->Size = window->SizeFull = size;
3685  }
3686  else
3687  {
3688  // Retrieve settings from .ini file
3689  // Use SetWindowPos() or SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
3690  window->PosFloat = ImVec2(60, 60);
3691  window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y);
3692 
3693  ImGuiIniData* settings = FindWindowSettings(name);
3694  if (!settings)
3695  {
3696  settings = AddWindowSettings(name);
3697  }
3698  else
3699  {
3703  }
3704 
3705  if (settings->Pos.x != FLT_MAX)
3706  {
3707  window->PosFloat = settings->Pos;
3708  window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y);
3709  window->Collapsed = settings->Collapsed;
3710  }
3711 
3712  if (ImLengthSqr(settings->Size) > 0.00001f && !(flags & ImGuiWindowFlags_NoResize))
3713  size = settings->Size;
3714  window->Size = window->SizeFull = size;
3715  }
3716 
3717  if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
3718  {
3719  window->AutoFitFramesX = window->AutoFitFramesY = 2;
3720  window->AutoFitOnlyGrows = false;
3721  }
3722  else
3723  {
3724  if (window->Size.x <= 0.0f)
3725  window->AutoFitFramesX = 2;
3726  if (window->Size.y <= 0.0f)
3727  window->AutoFitFramesY = 2;
3728  window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
3729  }
3730 
3732  g.Windows.insert(g.Windows.begin(), window); // Quite slow but rare and only once
3733  else
3734  g.Windows.push_back(window);
3735  return window;
3736 }
3737 
3739 {
3740  ImGuiContext& g = *GImGui;
3742  {
3743  // Using -1,-1 on either X/Y axis to preserve the current size.
3745  new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
3746  new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
3748  {
3751  data.Pos = window->Pos;
3752  data.CurrentSize = window->SizeFull;
3753  data.DesiredSize = new_size;
3755  new_size = data.DesiredSize;
3756  }
3757  }
3759  new_size = ImMax(new_size, g.Style.WindowMinSize);
3760  window->SizeFull = new_size;
3761 }
3762 
3763 // Push a new ImGui window to add widgets to.
3764 // - 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.
3765 // - Begin/End can be called multiple times during the frame with the same window name to append content.
3766 // - '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.
3767 // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
3768 // 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.
3769 // - 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.
3770 // - 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.
3771 // - Passing non-zero 'size' is roughly equivalent to calling SetNextWindowSize(size, ImGuiSetCond_FirstUseEver) prior to calling Begin().
3772 bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
3773 {
3774  return ImGui::Begin(name, p_open, ImVec2(0.f, 0.f), -1.0f, flags);
3775 }
3776 
3777 bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_on_first_use, float bg_alpha, ImGuiWindowFlags flags)
3778 {
3779  ImGuiContext& g = *GImGui;
3780  const ImGuiStyle& style = g.Style;
3781  IM_ASSERT(name != NULL); // Window name required
3782  IM_ASSERT(g.Initialized); // Forgot to call ImGui::NewFrame()
3783  IM_ASSERT(g.FrameCountEnded != g.FrameCount); // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
3784 
3785  if (flags & ImGuiWindowFlags_NoInputs)
3787 
3788  // Find or create
3789  bool window_is_new = false;
3791  if (!window)
3792  {
3793  window = CreateNewWindow(name, size_on_first_use, flags);
3794  window_is_new = true;
3795  }
3796 
3797  const int current_frame = ImGui::GetFrameCount();
3798  const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
3799  if (first_begin_of_the_frame)
3800  window->Flags = (ImGuiWindowFlags)flags;
3801  else
3802  flags = window->Flags;
3803 
3804  // Add to stack
3805  ImGuiWindow* parent_window = !g.CurrentWindowStack.empty() ? g.CurrentWindowStack.back() : NULL;
3806  g.CurrentWindowStack.push_back(window);
3807  SetCurrentWindow(window);
3808  CheckStacksSize(window, true);
3809  IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
3810 
3811  bool window_was_active = (window->LastFrameActive == current_frame - 1); // Not using !WasActive because the implicit "Debug" window would always toggle off->on
3812  if (flags & ImGuiWindowFlags_Popup)
3813  {
3815  window_was_active &= (window->PopupID == popup_ref.PopupID);
3816  window_was_active &= (window == popup_ref.Window);
3817  popup_ref.Window = window;
3818  g.CurrentPopupStack.push_back(popup_ref);
3819  window->PopupID = popup_ref.PopupID;
3820  }
3821 
3822  const bool window_appearing_after_being_hidden = (window->HiddenFrames == 1);
3823 
3824  // Process SetNextWindow***() calls
3825  bool window_pos_set_by_api = false, window_size_set_by_api = false;
3826  if (g.SetNextWindowPosCond)
3827  {
3828  const ImVec2 backup_cursor_pos = window->DC.CursorPos; // FIXME: not sure of the exact reason of this saving/restore anymore :( need to look into that.
3829  if (!window_was_active || window_appearing_after_being_hidden) window->SetWindowPosAllowFlags |= ImGuiSetCond_Appearing;
3830  window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.SetNextWindowPosCond) != 0;
3831  if (window_pos_set_by_api && ImLengthSqr(g.SetNextWindowPosVal - ImVec2(-FLT_MAX,-FLT_MAX)) < 0.001f)
3832  {
3833  window->SetWindowPosCenterWanted = true; // May be processed on the next frame if this is our first frame and we are measuring size
3835  }
3836  else
3837  {
3839  }
3840  window->DC.CursorPos = backup_cursor_pos;
3841  g.SetNextWindowPosCond = 0;
3842  }
3843  if (g.SetNextWindowSizeCond)
3844  {
3845  if (!window_was_active || window_appearing_after_being_hidden) window->SetWindowSizeAllowFlags |= ImGuiSetCond_Appearing;
3846  window_size_set_by_api = (window->SetWindowSizeAllowFlags & g.SetNextWindowSizeCond) != 0;
3848  g.SetNextWindowSizeCond = 0;
3849  }
3851  {
3854  }
3855  else if (first_begin_of_the_frame)
3856  {
3857  window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
3858  }
3860  {
3861  if (!window_was_active || window_appearing_after_being_hidden) window->SetWindowCollapsedAllowFlags |= ImGuiSetCond_Appearing;
3864  }
3865  if (g.SetNextWindowFocus)
3866  {
3868  g.SetNextWindowFocus = false;
3869  }
3870 
3871  // Update known root window (if we are a child window, otherwise window == window->RootWindow)
3872  int root_idx, root_non_popup_idx;
3873  for (root_idx = g.CurrentWindowStack.Size - 1; root_idx > 0; root_idx--)
3874  if (!(g.CurrentWindowStack[root_idx]->Flags & ImGuiWindowFlags_ChildWindow))
3875  break;
3876  for (root_non_popup_idx = root_idx; root_non_popup_idx > 0; root_non_popup_idx--)
3877  if (!(g.CurrentWindowStack[root_non_popup_idx]->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
3878  break;
3879  window->ParentWindow = parent_window;
3880  window->RootWindow = g.CurrentWindowStack[root_idx];
3881  window->RootNonPopupWindow = g.CurrentWindowStack[root_non_popup_idx]; // This is merely for displaying the TitleBgActive color.
3882 
3883  // When reusing window again multiple times a frame, just append content (don't need to setup again)
3884  if (first_begin_of_the_frame)
3885  {
3886  window->Active = true;
3887  window->IndexWithinParent = 0;
3888  window->BeginCount = 0;
3889  window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
3890  window->LastFrameActive = current_frame;
3891  window->IDStack.resize(1);
3892 
3893  // Clear draw list, setup texture, outer clipping rectangle
3894  window->DrawList->Clear();
3896  ImRect fullscreen_rect(GetVisibleRect());
3897  if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_ComboBox|ImGuiWindowFlags_Popup)))
3898  PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true);
3899  else
3900  PushClipRect(fullscreen_rect.Min, fullscreen_rect.Max, true);
3901 
3902  // New windows appears in front
3903  if (!window_was_active)
3904  {
3905  window->AutoPosLastDirection = -1;
3906 
3907  if (!(flags & ImGuiWindowFlags_NoFocusOnAppearing))
3908  if (!(flags & (ImGuiWindowFlags_ChildWindow|ImGuiWindowFlags_Tooltip)) || (flags & ImGuiWindowFlags_Popup))
3909  FocusWindow(window);
3910 
3911  // Popup first latch mouse position, will position itself when it appears next frame
3912  if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
3913  window->PosFloat = g.IO.MousePos;
3914  }
3915 
3916  // Collapse window by double-clicking on title bar
3917  // 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
3918  if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
3919  {
3920  ImRect title_bar_rect = window->TitleBarRect();
3921  if (g.HoveredWindow == window && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])
3922  {
3923  window->Collapsed = !window->Collapsed;
3924  if (!(flags & ImGuiWindowFlags_NoSavedSettings))
3926  FocusWindow(window);
3927  }
3928  }
3929  else
3930  {
3931  window->Collapsed = false;
3932  }
3933 
3934  // SIZE
3935 
3936  // Save contents size from last frame for auto-fitting (unless explicitly specified)
3937  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));
3938  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));
3939 
3940  // Hide popup/tooltip window when first appearing while we measure size (because we recycle them)
3941  if (window->HiddenFrames > 0)
3942  window->HiddenFrames--;
3943  if ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0 && !window_was_active)
3944  {
3945  window->HiddenFrames = 1;
3947  {
3948  if (!window_size_set_by_api)
3949  window->Size = window->SizeFull = ImVec2(0.f, 0.f);
3950  window->SizeContents = ImVec2(0.f, 0.f);
3951  }
3952  }
3953 
3954  // Lock window padding so that altering the ShowBorders flag for children doesn't have side-effects.
3956 
3957  // Calculate auto-fit size
3958  ImVec2 size_auto_fit;
3959  if ((flags & ImGuiWindowFlags_Tooltip) != 0)
3960  {
3961  // Tooltip always resize. We keep the spacing symmetric on both axises for aesthetic purpose.
3962  size_auto_fit = window->SizeContents + window->WindowPadding - ImVec2(0.0f, style.ItemSpacing.y);
3963  }
3964  else
3965  {
3966  size_auto_fit = ImClamp(window->SizeContents + window->WindowPadding, style.WindowMinSize, ImMax(style.WindowMinSize, g.IO.DisplaySize - g.Style.DisplaySafeAreaPadding));
3967 
3968  // Handling case of auto fit window not fitting in screen on one axis, we are growing auto fit size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than DisplaySize-WindowPadding.
3969  if (size_auto_fit.x < window->SizeContents.x && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar))
3970  size_auto_fit.y += style.ScrollbarSize;
3971  if (size_auto_fit.y < window->SizeContents.y && !(flags & ImGuiWindowFlags_NoScrollbar))
3972  size_auto_fit.x += style.ScrollbarSize;
3973  size_auto_fit.y = ImMax(size_auto_fit.y - style.ItemSpacing.y, 0.0f);
3974  }
3975 
3976  // Handle automatic resize
3977  if (window->Collapsed)
3978  {
3979  // We still process initial auto-fit on collapsed windows to get a window width,
3980  // But otherwise we don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
3981  if (window->AutoFitFramesX > 0)
3982  window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
3983  if (window->AutoFitFramesY > 0)
3984  window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
3985  }
3986  else
3987  {
3988  if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window_size_set_by_api)
3989  {
3990  window->SizeFull = size_auto_fit;
3991  }
3992  else if ((window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0) && !window_size_set_by_api)
3993  {
3994  // Auto-fit only grows during the first few frames
3995  if (window->AutoFitFramesX > 0)
3996  window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
3997  if (window->AutoFitFramesY > 0)
3998  window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
3999  if (!(flags & ImGuiWindowFlags_NoSavedSettings))
4001  }
4002  }
4003 
4004  // Apply minimum/maximum window size constraints and final size
4005  ApplySizeFullWithConstraint(window, window->SizeFull);
4006  window->Size = window->Collapsed ? window->TitleBarRect().GetSize() : window->SizeFull;
4007 
4008  // POSITION
4009 
4010  // Position child window
4011  if (flags & ImGuiWindowFlags_ChildWindow)
4012  {
4013  window->IndexWithinParent = parent_window->DC.ChildWindows.Size;
4014  parent_window->DC.ChildWindows.push_back(window);
4015  }
4016  if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup))
4017  {
4018  window->Pos = window->PosFloat = parent_window->DC.CursorPos;
4019  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().
4020  }
4021 
4022  bool window_pos_center = false;
4023  window_pos_center |= (window->SetWindowPosCenterWanted && window->HiddenFrames == 0);
4024  window_pos_center |= ((flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api && window_appearing_after_being_hidden);
4025  if (window_pos_center)
4026  {
4027  // Center (any sort of window)
4028  SetWindowPos(ImMax(style.DisplaySafeAreaPadding, fullscreen_rect.GetCenter() - window->SizeFull * 0.5f));
4029  }
4030  else if (flags & ImGuiWindowFlags_ChildMenu)
4031  {
4032  IM_ASSERT(window_pos_set_by_api);
4033  ImRect rect_to_avoid;
4034  if (parent_window->DC.MenuBarAppending)
4035  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());
4036  else
4037  rect_to_avoid = ImRect(parent_window->Pos.x + style.ItemSpacing.x, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - style.ItemSpacing.x - parent_window->ScrollbarSizes.x, FLT_MAX); // We want some overlap to convey the relative depth of each popup (here hard-coded to 4)
4038  window->PosFloat = FindBestPopupWindowPos(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
4039  }
4040  else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_appearing_after_being_hidden)
4041  {
4042  ImRect rect_to_avoid(window->PosFloat.x - 1, window->PosFloat.y - 1, window->PosFloat.x + 1, window->PosFloat.y + 1);
4043  window->PosFloat = FindBestPopupWindowPos(window->PosFloat, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
4044  }
4045 
4046  // Position tooltip (always follows mouse)
4047  if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api)
4048  {
4049  ImRect rect_to_avoid(g.IO.MousePos.x - 16, g.IO.MousePos.y - 8, g.IO.MousePos.x + 24, g.IO.MousePos.y + 24); // FIXME: Completely hard-coded. Perhaps center on cursor hit-point instead?
4050  window->PosFloat = FindBestPopupWindowPos(g.IO.MousePos, window->Size, &window->AutoPosLastDirection, rect_to_avoid);
4051  if (window->AutoPosLastDirection == -1)
4052  window->PosFloat = g.IO.MousePos + 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.
4053  }
4054 
4055  // Clamp position so it stays visible
4056  if (!(flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
4057  {
4058  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.
4059  {
4060  ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
4061  window->PosFloat = ImMax(window->PosFloat + window->Size, padding) - window->Size;
4062  window->PosFloat = ImMin(window->PosFloat, g.IO.DisplaySize - padding);
4063  }
4064  }
4065  window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y);
4066 
4067  // Default item width. Make it proportional to window size if window manually resizes
4068  if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
4069  window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
4070  else
4071  window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
4072 
4073  // Prepare for focus requests
4074  window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1);
4075  window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1);
4076  window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1;
4077  window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX;
4078 
4079  // Apply scrolling
4080  if (window->ScrollTarget.x < FLT_MAX)
4081  {
4082  window->Scroll.x = window->ScrollTarget.x;
4083  window->ScrollTarget.x = FLT_MAX;
4084  }
4085  if (window->ScrollTarget.y < FLT_MAX)
4086  {
4087  float center_ratio = window->ScrollTargetCenterRatio.y;
4088  window->Scroll.y = window->ScrollTarget.y - ((1.0f - center_ratio) * window->TitleBarHeight()) - (center_ratio * window->SizeFull.y);
4089  window->ScrollTarget.y = FLT_MAX;
4090  }
4091  window->Scroll = ImMax(window->Scroll, ImVec2(0.0f, 0.0f));
4092  if (!window->Collapsed && !window->SkipItems)
4093  window->Scroll = ImMin(window->Scroll, ImMax(ImVec2(0.0f, 0.0f), window->SizeContents - window->SizeFull + window->ScrollbarSizes));
4094 
4095  // Modal window darkens what is behind them
4096  if ((flags & ImGuiWindowFlags_Modal) != 0 && window == GetFrontMostModalRootWindow())
4097  window->DrawList->AddRectFilled(fullscreen_rect.Min, fullscreen_rect.Max, GetColorU32(ImGuiCol_ModalWindowDarkening, g.ModalWindowDarkeningRatio));
4098 
4099  // Draw window + handle manual resize
4100  ImRect title_bar_rect = window->TitleBarRect();
4101  const float window_rounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding;
4102  if (window->Collapsed)
4103  {
4104  // Draw title bar only
4105  RenderFrame(title_bar_rect.GetTL(), title_bar_rect.GetBR(), GetColorU32(ImGuiCol_TitleBgCollapsed), true, window_rounding);
4106  }
4107  else
4108  {
4109  ImU32 resize_col = 0;
4110  const float resize_corner_size = ImMax(g.FontSize * 1.35f, window_rounding + 1.0f + g.FontSize * 0.2f);
4111  if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && !(flags & ImGuiWindowFlags_NoResize))
4112  {
4113  // Manual resize
4114  const ImVec2 br = window->Rect().GetBR();
4115  const ImRect resize_rect(br - ImVec2(resize_corner_size * 0.75f, resize_corner_size * 0.75f), br);
4116  const ImGuiID resize_id = window->GetID("#RESIZE");
4117  bool hovered, held;
4118  ButtonBehavior(resize_rect, resize_id, &hovered, &held, ImGuiButtonFlags_FlattenChilds);
4120 
4121  if (hovered || held)
4123 
4124  if (g.HoveredWindow == window && held && g.IO.MouseDoubleClicked[0])
4125  {
4126  // Manual auto-fit when double-clicking
4127  ApplySizeFullWithConstraint(window, size_auto_fit);
4128  if (!(flags & ImGuiWindowFlags_NoSavedSettings))
4130  SetActiveID(0);
4131  }
4132  else if (held)
4133  {
4134  // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
4135  ApplySizeFullWithConstraint(window, (g.IO.MousePos - g.ActiveIdClickOffset + resize_rect.GetSize()) - window->Pos);
4136  if (!(flags & ImGuiWindowFlags_NoSavedSettings))
4138  }
4139 
4140  window->Size = window->SizeFull;
4141  title_bar_rect = window->TitleBarRect();
4142  }
4143 
4144  // Scrollbars
4145  window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > window->Size.y + style.ItemSpacing.y) && !(flags & ImGuiWindowFlags_NoScrollbar));
4146  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));
4147  window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
4148  window->BorderSize = (flags & ImGuiWindowFlags_ShowBorders) ? 1.0f : 0.0f;
4149 
4150  // Window background
4151  // Default alpha
4152  ImGuiCol bg_color_idx = ImGuiCol_WindowBg;
4153  if ((flags & ImGuiWindowFlags_ComboBox) != 0)
4154  bg_color_idx = ImGuiCol_ComboBg;
4155  else if ((flags & ImGuiWindowFlags_Tooltip) != 0 || (flags & ImGuiWindowFlags_Popup) != 0)
4156  bg_color_idx = ImGuiCol_PopupBg;
4157  else if ((flags & ImGuiWindowFlags_ChildWindow) != 0)
4158  bg_color_idx = ImGuiCol_ChildWindowBg;
4159  ImVec4 bg_color = style.Colors[bg_color_idx];
4160  if (bg_alpha >= 0.0f)
4161  bg_color.w = bg_alpha;
4162  bg_color.w *= style.Alpha;
4163  if (bg_color.w > 0.0f)
4164  window->DrawList->AddRectFilled(window->Pos+ImVec2(0,window->TitleBarHeight()), window->Pos+window->Size, ColorConvertFloat4ToU32(bg_color), window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 15 : 4|8);
4165 
4166  // Title bar
4167  if (!(flags & ImGuiWindowFlags_NoTitleBar))
4168  window->DrawList->AddRectFilled(title_bar_rect.GetTL(), title_bar_rect.GetBR(), GetColorU32((g.FocusedWindow && window->RootNonPopupWindow == g.FocusedWindow->RootNonPopupWindow) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg), window_rounding, 1|2);
4169 
4170  // Menu bar
4171  if (flags & ImGuiWindowFlags_MenuBar)
4172  {
4173  ImRect menu_bar_rect = window->MenuBarRect();
4174  window->DrawList->AddRectFilled(menu_bar_rect.GetTL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, 1|2);
4175  if (flags & ImGuiWindowFlags_ShowBorders)
4176  window->DrawList->AddLine(menu_bar_rect.GetBL()-ImVec2(0,0), menu_bar_rect.GetBR()-ImVec2(0,0), GetColorU32(ImGuiCol_Border));
4177  }
4178 
4179  // Scrollbars
4180  if (window->ScrollbarX)
4181  Scrollbar(window, true);
4182  if (window->ScrollbarY)
4183  Scrollbar(window, false);
4184 
4185  // Render resize grip
4186  // (after the input handling so we don't have a frame of latency)
4187  if (!(flags & ImGuiWindowFlags_NoResize))
4188  {
4189  const ImVec2 br = window->Rect().GetBR();
4190  window->DrawList->PathLineTo(br + ImVec2(-resize_corner_size, -window->BorderSize));
4191  window->DrawList->PathLineTo(br + ImVec2(-window->BorderSize, -resize_corner_size));
4192  window->DrawList->PathArcToFast(ImVec2(br.x - window_rounding - window->BorderSize, br.y - window_rounding - window->BorderSize), window_rounding, 0, 3);
4193  window->DrawList->PathFill(resize_col);
4194  }
4195 
4196  // Borders
4197  if (flags & ImGuiWindowFlags_ShowBorders)
4198  {
4199  window->DrawList->AddRect(window->Pos+ImVec2(1,1), window->Pos+window->Size+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), window_rounding);
4200  window->DrawList->AddRect(window->Pos, window->Pos+window->Size, GetColorU32(ImGuiCol_Border), window_rounding);
4201  if (!(flags & ImGuiWindowFlags_NoTitleBar))
4202  window->DrawList->AddLine(title_bar_rect.GetBL()+ImVec2(1,0), title_bar_rect.GetBR()-ImVec2(1,0), GetColorU32(ImGuiCol_Border));
4203  }
4204  }
4205 
4206  // Update ContentsRegionMax. All the variable it depends on are set above in this function.
4207  window->ContentsRegionRect.Min.x = -window->Scroll.x + window->WindowPadding.x;
4208  window->ContentsRegionRect.Min.x = -window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight();
4209  window->ContentsRegionRect.Max.x = -window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x));
4210  window->ContentsRegionRect.Max.y = -window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y));
4211 
4212  // Setup drawing context
4213  window->DC.IndentX = 0.0f + window->WindowPadding.x - window->Scroll.x;
4214  window->DC.ColumnsOffsetX = 0.0f;
4215  window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.IndentX + window->DC.ColumnsOffsetX, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
4216  window->DC.CursorPos = window->DC.CursorStartPos;
4217  window->DC.CursorPosPrevLine = window->DC.CursorPos;
4218  window->DC.CursorMaxPos = window->DC.CursorStartPos;
4219  window->DC.CurrentLineHeight = window->DC.PrevLineHeight = 0.0f;
4220  window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
4221  window->DC.MenuBarAppending = false;
4222  window->DC.MenuBarOffsetX = ImMax(window->WindowPadding.x, style.ItemSpacing.x);
4223  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
4224  window->DC.ChildWindows.resize(0);
4226  window->DC.ItemWidth = window->ItemWidthDefault;
4227  window->DC.TextWrapPos = -1.0f; // disabled
4228  window->DC.AllowKeyboardFocus = true;
4229  window->DC.ButtonRepeat = false;
4230  window->DC.ItemWidthStack.resize(0);
4231  window->DC.TextWrapPosStack.resize(0);
4232  window->DC.AllowKeyboardFocusStack.resize(0);
4233  window->DC.ButtonRepeatStack.resize(0);
4235  window->DC.ColumnsCurrent = 0;
4236  window->DC.ColumnsCount = 1;
4237  window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
4238  window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.ColumnsStartPosY;
4239  window->DC.TreeDepth = 0;
4240  window->DC.StateStorage = &window->StateStorage;
4241  window->DC.GroupStack.resize(0);
4242  window->MenuColumns.Update(3, style.ItemSpacing.x, !window_was_active);
4243 
4244  if (window->AutoFitFramesX > 0)
4245  window->AutoFitFramesX--;
4246  if (window->AutoFitFramesY > 0)
4247  window->AutoFitFramesY--;
4248 
4249  // Title bar
4250  if (!(flags & ImGuiWindowFlags_NoTitleBar))
4251  {
4252  if (p_open != NULL)
4253  {
4254  const float pad = 2.0f;
4255  const float rad = (window->TitleBarHeight() - pad*2.0f) * 0.5f;
4256  if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad))
4257  *p_open = false;
4258  }
4259 
4260  const ImVec2 text_size = CalcTextSize(name, NULL, true);
4261  if (!(flags & ImGuiWindowFlags_NoCollapse))
4262  RenderCollapseTriangle(window->Pos + style.FramePadding, !window->Collapsed, 1.0f, true);
4263 
4264  ImVec2 text_min = window->Pos + style.FramePadding;
4265  ImVec2 text_max = window->Pos + ImVec2(window->Size.x - style.FramePadding.x, style.FramePadding.y*2 + text_size.y);
4266  ImVec2 clip_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()
4267  bool pad_left = (flags & ImGuiWindowFlags_NoCollapse) == 0;