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;
4268  bool pad_right = (p_open != NULL);
4269  if (style.WindowTitleAlign & ImGuiAlign_Center) pad_right = pad_left;
4270  if (pad_left) text_min.x += g.FontSize + style.ItemInnerSpacing.x;
4271  if (pad_right) text_max.x -= g.FontSize + style.ItemInnerSpacing.x;
4272  RenderTextClipped(text_min, text_max, name, NULL, &text_size, style.WindowTitleAlign, NULL, &clip_max);
4273  }
4274 
4275  // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
4276  window->WindowRectClipped = window->Rect();
4277  window->WindowRectClipped.Clip(window->ClipRect);
4278 
4279  // Pressing CTRL+C while holding on a window copy its content to the clipboard
4280  // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
4281  // Maybe we can support CTRL+C on every element?
4282  /*
4283  if (g.ActiveId == move_id)
4284  if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
4285  ImGui::LogToClipboard();
4286  */
4287  }
4288 
4289  // Inner clipping rectangle
4290  // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
4291  // Note that if our window is collapsed we will end up with a null clipping rectangle which is the correct behavior.
4292  const ImRect title_bar_rect = window->TitleBarRect();
4293  const float border_size = window->BorderSize;
4294  ImRect clip_rect; // Force round to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
4295  clip_rect.Min.x = ImFloor(0.5f + title_bar_rect.Min.x + ImMax(border_size, ImFloor(window->WindowPadding.x*0.5f)));
4296  clip_rect.Min.y = ImFloor(0.5f + title_bar_rect.Max.y + window->MenuBarHeight() + border_size);
4297  clip_rect.Max.x = ImFloor(0.5f + window->Pos.x + window->Size.x - window->ScrollbarSizes.x - ImMax(border_size, ImFloor(window->WindowPadding.x*0.5f)));
4298  clip_rect.Max.y = ImFloor(0.5f + window->Pos.y + window->Size.y - window->ScrollbarSizes.y - border_size);
4299  PushClipRect(clip_rect.Min, clip_rect.Max, true);
4300 
4301  // Clear 'accessed' flag last thing
4302  if (first_begin_of_the_frame)
4303  window->Accessed = false;
4304  window->BeginCount++;
4305  g.SetNextWindowSizeConstraint = false;
4306 
4307  // Child window can be out of sight and have "negative" clip windows.
4308  // Mark them as collapsed so commands are skipped earlier (we can't manually collapse because they have no title bar).
4309  if (flags & ImGuiWindowFlags_ChildWindow)
4310  {
4311  IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
4312  window->Collapsed = parent_window && parent_window->Collapsed;
4313 
4314  if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
4315  window->Collapsed |= (window->WindowRectClipped.Min.x >= window->WindowRectClipped.Max.x || window->WindowRectClipped.Min.y >= window->WindowRectClipped.Max.y);
4316 
4317  // We also hide the window from rendering because we've already added its border to the command list.
4318  // (we could perform the check earlier in the function but it is simpler at this point)
4319  if (window->Collapsed)
4320  window->Active = false;
4321  }
4322  if (style.Alpha <= 0.0f)
4323  window->Active = false;
4324 
4325  // Return false if we don't intend to display anything to allow user to perform an early out optimization
4326  window->SkipItems = (window->Collapsed || !window->Active) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0;
4327  return !window->SkipItems;
4328 }
4329 
4331 {
4332  ImGuiContext& g = *GImGui;
4334 
4335  Columns(1, "#CloseColumns");
4336  PopClipRect(); // inner window clip rectangle
4337 
4338  // Stop logging
4339  if (!(window->Flags & ImGuiWindowFlags_ChildWindow)) // FIXME: add more options for scope of logging
4340  LogFinish();
4341 
4342  // Pop
4343  // NB: we don't clear 'window->RootWindow'. The pointer is allowed to live until the next call to Begin().
4345  if (window->Flags & ImGuiWindowFlags_Popup)
4347  CheckStacksSize(window, false);
4349 }
4350 
4351 // Vertical scrollbar
4352 // The entire piece of code below is rather confusing because:
4353 // - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
4354 // - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
4355 // - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
4357 {
4358  ImGuiContext& g = *GImGui;
4359  const ImGuiStyle& style = g.Style;
4360  const ImGuiID id = window->GetID(horizontal ? "#SCROLLX" : "#SCROLLY");
4361 
4362  // Render background
4363  bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
4364  float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f;
4365  const ImRect window_rect = window->Rect();
4366  const float border_size = window->BorderSize;
4367  ImRect bb = horizontal
4368  ? ImRect(window->Pos.x + border_size, window_rect.Max.y - style.ScrollbarSize, window_rect.Max.x - other_scrollbar_size_w - border_size, window_rect.Max.y - border_size)
4369  : ImRect(window_rect.Max.x - style.ScrollbarSize, window->Pos.y + border_size, window_rect.Max.x - border_size, window_rect.Max.y - other_scrollbar_size_w - border_size);
4370  if (!horizontal)
4371  bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f);
4372 
4373  float window_rounding = (window->Flags & ImGuiWindowFlags_ChildWindow) ? style.ChildWindowRounding : style.WindowRounding;
4374  int window_rounding_corners;
4375  if (horizontal)
4376  window_rounding_corners = 8 | (other_scrollbar ? 0 : 4);
4377  else
4378  window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? 2 : 0) | (other_scrollbar ? 0 : 4);
4379  window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_ScrollbarBg), window_rounding, window_rounding_corners);
4380  bb.Reduce(ImVec2(ImClamp((float)(int)((bb.Max.x - bb.Min.x - 2.0f) * 0.5f), 0.0f, 3.0f), ImClamp((float)(int)((bb.Max.y - bb.Min.y - 2.0f) * 0.5f), 0.0f, 3.0f)));
4381 
4382  // V denote the main axis of the scrollbar
4383  float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
4384  float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y;
4385  float win_size_avail_v = (horizontal ? window->Size.x : window->Size.y) - other_scrollbar_size_w;
4386  float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y;
4387 
4388  // The grabable box size generally represent the amount visible (vs the total scrollable amount)
4389  // But we maintain a minimum size in pixel to allow for the user to still aim inside.
4390  const float grab_h_pixels = ImMin(ImMax(scrollbar_size_v * ImSaturate(win_size_avail_v / ImMax(win_size_contents_v, win_size_avail_v)), style.GrabMinSize), scrollbar_size_v);
4391  const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
4392 
4393  // Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
4394  bool held = false;
4395  bool hovered = false;
4396  const bool previously_held = (g.ActiveId == id);
4397  ImGui::ButtonBehavior(bb, id, &hovered, &held);
4398 
4399  float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v);
4400  float scroll_ratio = ImSaturate(scroll_v / scroll_max);
4401  float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
4402  if (held && grab_h_norm < 1.0f)
4403  {
4404  float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y;
4405  float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
4406  float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y;
4407 
4408  // Click position in scrollbar normalized space (0.0f->1.0f)
4409  const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);
4410  ImGui::SetHoveredID(id);
4411 
4412  bool seek_absolute = false;
4413  if (!previously_held)
4414  {
4415  // On initial click calculate the distance between mouse and the center of the grab
4416  if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm)
4417  {
4418  *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
4419  }
4420  else
4421  {
4422  seek_absolute = true;
4423  *click_delta_to_grab_center_v = 0.0f;
4424  }
4425  }
4426 
4427  // Apply scroll
4428  // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position
4429  const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm*0.5f) / (1.0f - grab_h_norm));
4430  scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
4431  if (horizontal)
4432  window->Scroll.x = scroll_v;
4433  else
4434  window->Scroll.y = scroll_v;
4435 
4436  // Update values for rendering
4437  scroll_ratio = ImSaturate(scroll_v / scroll_max);
4438  grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
4439 
4440  // Update distance to grab now that we have seeked and saturated
4441  if (seek_absolute)
4442  *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
4443  }
4444 
4445  // Render
4447  if (horizontal)
4448  window->DrawList->AddRectFilled(ImVec2(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y), ImVec2(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y), grab_col, style.ScrollbarRounding);
4449  else
4450  window->DrawList->AddRectFilled(ImVec2(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm)), ImVec2(bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels), grab_col, style.ScrollbarRounding);
4451 }
4452 
4453 // Moving window to front of display (which happens to be back of our sorted list)
4455 {
4456  ImGuiContext& g = *GImGui;
4457 
4458  // Always mark the window we passed as focused. This is used for keyboard interactions such as tabbing.
4459  g.FocusedWindow = window;
4460 
4461  // Passing NULL allow to disable keyboard focus
4462  if (!window)
4463  return;
4464 
4465  // And move its root window to the top of the pile
4466  if (window->RootWindow)
4467  window = window->RootWindow;
4468 
4469  // Steal focus on active widgets
4470  if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it..
4471  if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window)
4472  SetActiveID(0);
4473 
4474  // Bring to front
4476  return;
4477  for (int i = 0; i < g.Windows.Size; i++)
4478  if (g.Windows[i] == window)
4479  {
4480  g.Windows.erase(g.Windows.begin() + i);
4481  break;
4482  }
4483  g.Windows.push_back(window);
4484 }
4485 
4486 void ImGui::PushItemWidth(float item_width)
4487 {
4489  window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
4490  window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
4491 }
4492 
4493 static void PushMultiItemsWidths(int components, float w_full)
4494 {
4496  const ImGuiStyle& style = GImGui->Style;
4497  if (w_full <= 0.0f)
4498  w_full = ImGui::CalcItemWidth();
4499  const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
4500  const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
4501  window->DC.ItemWidthStack.push_back(w_item_last);
4502  for (int i = 0; i < components-1; i++)
4503  window->DC.ItemWidthStack.push_back(w_item_one);
4504  window->DC.ItemWidth = window->DC.ItemWidthStack.back();
4505 }
4506 
4508 {
4510  window->DC.ItemWidthStack.pop_back();
4511  window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
4512 }
4513 
4515 {
4517  float w = window->DC.ItemWidth;
4518  if (w < 0.0f)
4519  {
4520  // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well.
4521  float width_to_right_edge = GetContentRegionAvail().x;
4522  w = ImMax(1.0f, width_to_right_edge + w);
4523  }
4524  w = (float)(int)w;
4525  return w;
4526 }
4527 
4529 {
4530  ImGuiContext& g = *GImGui;
4531  IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
4532  IM_ASSERT(font->Scale > 0.0f);
4533  g.Font = font;
4535  g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
4537 }
4538 
4540 {
4541  ImGuiContext& g = *GImGui;
4542  if (!font)
4543  font = g.IO.Fonts->Fonts[0];
4544  SetCurrentFont(font);
4545  g.FontStack.push_back(font);
4547 }
4548 
4550 {
4551  ImGuiContext& g = *GImGui;
4553  g.FontStack.pop_back();
4555 }
4556 
4557 void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
4558 {
4560  window->DC.AllowKeyboardFocus = allow_keyboard_focus;
4561  window->DC.AllowKeyboardFocusStack.push_back(allow_keyboard_focus);
4562 }
4563 
4565 {
4568  window->DC.AllowKeyboardFocus = window->DC.AllowKeyboardFocusStack.empty() ? true : window->DC.AllowKeyboardFocusStack.back();
4569 }
4570 
4572 {
4574  window->DC.ButtonRepeat = repeat;
4575  window->DC.ButtonRepeatStack.push_back(repeat);
4576 }
4577 
4579 {
4581  window->DC.ButtonRepeatStack.pop_back();
4582  window->DC.ButtonRepeat = window->DC.ButtonRepeatStack.empty() ? false : window->DC.ButtonRepeatStack.back();
4583 }
4584 
4585 void ImGui::PushTextWrapPos(float wrap_pos_x)
4586 {
4588  window->DC.TextWrapPos = wrap_pos_x;
4589  window->DC.TextWrapPosStack.push_back(wrap_pos_x);
4590 }
4591 
4593 {
4595  window->DC.TextWrapPosStack.pop_back();
4596  window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
4597 }
4598 
4600 {
4601  ImGuiContext& g = *GImGui;
4602  ImGuiColMod backup;
4603  backup.Col = idx;
4604  backup.PreviousValue = g.Style.Colors[idx];
4605  g.ColorModifiers.push_back(backup);
4606  g.Style.Colors[idx] = col;
4607 }
4608 
4610 {
4611  ImGuiContext& g = *GImGui;
4612  while (count > 0)
4613  {
4614  ImGuiColMod& backup = g.ColorModifiers.back();
4615  g.Style.Colors[backup.Col] = backup.PreviousValue;
4617  count--;
4618  }
4619 }
4620 
4622 {
4623  ImGuiContext& g = *GImGui;
4624  switch (idx)
4625  {
4626  case ImGuiStyleVar_Alpha: return &g.Style.Alpha;
4632  }
4633  return NULL;
4634 }
4635 
4637 {
4638  ImGuiContext& g = *GImGui;
4639  switch (idx)
4640  {
4646  }
4647  return NULL;
4648 }
4649 
4651 {
4652  ImGuiContext& g = *GImGui;
4653  float* pvar = GetStyleVarFloatAddr(idx);
4654  IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a float.
4655  ImGuiStyleMod backup;
4656  backup.Var = idx;
4657  backup.PreviousValue = ImVec2(*pvar, 0.0f);
4658  g.StyleModifiers.push_back(backup);
4659  *pvar = val;
4660 }
4661 
4662 
4664 {
4665  ImGuiContext& g = *GImGui;
4666  ImVec2* pvar = GetStyleVarVec2Addr(idx);
4667  IM_ASSERT(pvar != NULL); // Called function with wrong-type? Variable is not a ImVec2.
4668  ImGuiStyleMod backup;
4669  backup.Var = idx;
4670  backup.PreviousValue = *pvar;
4671  g.StyleModifiers.push_back(backup);
4672  *pvar = val;
4673 }
4674 
4676 {
4677  ImGuiContext& g = *GImGui;
4678  while (count > 0)
4679  {
4680  ImGuiStyleMod& backup = g.StyleModifiers.back();
4681  if (float* pvar_f = GetStyleVarFloatAddr(backup.Var))
4682  *pvar_f = backup.PreviousValue.x;
4683  else if (ImVec2* pvar_v = GetStyleVarVec2Addr(backup.Var))
4684  *pvar_v = backup.PreviousValue;
4686  count--;
4687  }
4688 }
4689 
4691 {
4692  // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
4693  switch (idx)
4694  {
4695  case ImGuiCol_Text: return "Text";
4696  case ImGuiCol_TextDisabled: return "TextDisabled";
4697  case ImGuiCol_WindowBg: return "WindowBg";
4698  case ImGuiCol_ChildWindowBg: return "ChildWindowBg";
4699  case ImGuiCol_PopupBg: return "PopupBg";
4700  case ImGuiCol_Border: return "Border";
4701  case ImGuiCol_BorderShadow: return "BorderShadow";
4702  case ImGuiCol_FrameBg: return "FrameBg";
4703  case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
4704  case ImGuiCol_FrameBgActive: return "FrameBgActive";
4705  case ImGuiCol_TitleBg: return "TitleBg";
4706  case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
4707  case ImGuiCol_TitleBgActive: return "TitleBgActive";
4708  case ImGuiCol_MenuBarBg: return "MenuBarBg";
4709  case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
4710  case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
4711  case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
4712  case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
4713  case ImGuiCol_ComboBg: return "ComboBg";
4714  case ImGuiCol_CheckMark: return "CheckMark";
4715  case ImGuiCol_SliderGrab: return "SliderGrab";
4716  case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
4717  case ImGuiCol_Button: return "Button";
4718  case ImGuiCol_ButtonHovered: return "ButtonHovered";
4719  case ImGuiCol_ButtonActive: return "ButtonActive";
4720  case ImGuiCol_Header: return "Header";
4721  case ImGuiCol_HeaderHovered: return "HeaderHovered";
4722  case ImGuiCol_HeaderActive: return "HeaderActive";
4723  case ImGuiCol_Column: return "Column";
4724  case ImGuiCol_ColumnHovered: return "ColumnHovered";
4725  case ImGuiCol_ColumnActive: return "ColumnActive";
4726  case ImGuiCol_ResizeGrip: return "ResizeGrip";
4727  case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
4728  case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
4729  case ImGuiCol_CloseButton: return "CloseButton";
4730  case ImGuiCol_CloseButtonHovered: return "CloseButtonHovered";
4731  case ImGuiCol_CloseButtonActive: return "CloseButtonActive";
4732  case ImGuiCol_PlotLines: return "PlotLines";
4733  case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
4734  case ImGuiCol_PlotHistogram: return "PlotHistogram";
4735  case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
4736  case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
4737  case ImGuiCol_ModalWindowDarkening: return "ModalWindowDarkening";
4738  }
4739  IM_ASSERT(0);
4740  return "Unknown";
4741 }
4742 
4744 {
4745  ImGuiContext& g = *GImGui;
4747 }
4748 
4750 {
4751  ImGuiContext& g = *GImGui;
4752  return g.FocusedWindow == g.CurrentWindow;
4753 }
4754 
4756 {
4757  ImGuiContext& g = *GImGui;
4758  return g.FocusedWindow == g.CurrentWindow->RootWindow;
4759 }
4760 
4762 {
4763  ImGuiContext& g = *GImGui;
4765 }
4766 
4768 {
4769  ImGuiContext& g = *GImGui;
4771 }
4772 
4774 {
4775  ImGuiWindow* window = GImGui->CurrentWindow;
4776  return window->Size.x;
4777 }
4778 
4780 {
4781  ImGuiWindow* window = GImGui->CurrentWindow;
4782  return window->Size.y;
4783 }
4784 
4786 {
4787  ImGuiContext& g = *GImGui;
4789  return window->Pos;
4790 }
4791 
4792 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
4793 {
4794  window->DC.CursorMaxPos.y += window->Scroll.y;
4795  window->Scroll.y = new_scroll_y;
4796  window->DC.CursorMaxPos.y -= window->Scroll.y;
4797 }
4798 
4800 {
4801  // Test condition (NB: bit 0 is always true) and clear flags for next time
4802  if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
4803  return;
4805  window->SetWindowPosCenterWanted = false;
4806 
4807  // Set
4808  const ImVec2 old_pos = window->Pos;
4809  window->PosFloat = pos;
4810  window->Pos = ImVec2((float)(int)window->PosFloat.x, (float)(int)window->PosFloat.y);
4811  window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
4812  window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected.
4813 }
4814 
4816 {
4818  SetWindowPos(window, pos, cond);
4819 }
4820 
4821 void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiSetCond cond)
4822 {
4824  if (window)
4825  SetWindowPos(window, pos, cond);
4826 }
4827 
4829 {
4831  return window->Size;
4832 }
4833 
4835 {
4836  // Test condition (NB: bit 0 is always true) and clear flags for next time
4837  if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
4838  return;
4840 
4841  // Set
4842  if (size.x > 0.0f)
4843  {
4844  window->AutoFitFramesX = 0;
4845  window->SizeFull.x = size.x;
4846  }
4847  else
4848  {
4849  window->AutoFitFramesX = 2;
4850  window->AutoFitOnlyGrows = false;
4851  }
4852  if (size.y > 0.0f)
4853  {
4854  window->AutoFitFramesY = 0;
4855  window->SizeFull.y = size.y;
4856  }
4857  else
4858  {
4859  window->AutoFitFramesY = 2;
4860  window->AutoFitOnlyGrows = false;
4861  }
4862 }
4863 
4865 {
4866  SetWindowSize(GImGui->CurrentWindow, size, cond);
4867 }
4868 
4869 void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiSetCond cond)
4870 {
4872  if (window)
4873  SetWindowSize(window, size, cond);
4874 }
4875 
4876 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiSetCond cond)
4877 {
4878  // Test condition (NB: bit 0 is always true) and clear flags for next time
4879  if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
4880  return;
4882 
4883  // Set
4884  window->Collapsed = collapsed;
4885 }
4886 
4887 void ImGui::SetWindowCollapsed(bool collapsed, ImGuiSetCond cond)
4888 {
4889  SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
4890 }
4891 
4893 {
4894  return GImGui->CurrentWindow->Collapsed;
4895 }
4896 
4897 void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiSetCond cond)
4898 {
4900  if (window)
4901  SetWindowCollapsed(window, collapsed, cond);
4902 }
4903 
4905 {
4906  FocusWindow(GImGui->CurrentWindow);
4907 }
4908 
4909 void ImGui::SetWindowFocus(const char* name)
4910 {
4911  if (name)
4912  {
4914  if (window)
4915  FocusWindow(window);
4916  }
4917  else
4918  {
4919  FocusWindow(NULL);
4920  }
4921 }
4922 
4924 {
4925  ImGuiContext& g = *GImGui;
4927  g.SetNextWindowPosCond = cond ? cond : ImGuiSetCond_Always;
4928 }
4929 
4931 {
4932  ImGuiContext& g = *GImGui;
4933  g.SetNextWindowPosVal = ImVec2(-FLT_MAX, -FLT_MAX);
4934  g.SetNextWindowPosCond = cond ? cond : ImGuiSetCond_Always;
4935 }
4936 
4938 {
4939  ImGuiContext& g = *GImGui;
4941  g.SetNextWindowSizeCond = cond ? cond : ImGuiSetCond_Always;
4942 }
4943 
4944 void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeConstraintCallback custom_callback, void* custom_callback_user_data)
4945 {
4946  ImGuiContext& g = *GImGui;
4947  g.SetNextWindowSizeConstraint = true;
4948  g.SetNextWindowSizeConstraintRect = ImRect(size_min, size_max);
4949  g.SetNextWindowSizeConstraintCallback = custom_callback;
4950  g.SetNextWindowSizeConstraintCallbackUserData = custom_callback_user_data;
4951 }
4952 
4954 {
4955  ImGuiContext& g = *GImGui;
4958 }
4959 
4961 {
4962  ImGuiContext& g = *GImGui;
4965 }
4966 
4968 {
4969  ImGuiContext& g = *GImGui;
4970  g.SetNextWindowCollapsedVal = collapsed;
4972 }
4973 
4975 {
4976  ImGuiContext& g = *GImGui;
4977  g.SetNextWindowFocus = true;
4978 }
4979 
4980 // In window space (not screen space!)
4982 {
4984  ImVec2 mx = window->ContentsRegionRect.Max;
4985  if (window->DC.ColumnsCount != 1)
4986  mx.x = GetColumnOffset(window->DC.ColumnsCurrent + 1) - window->WindowPadding.x;
4987  return mx;
4988 }
4989 
4991 {
4993  window->ContentsRegionRect.Max.x = x;
4994  window->Size.x = x;
4995 }
4996 
4998 {
5000  return GetContentRegionMax() - (window->DC.CursorPos - window->Pos);
5001 }
5002 
5004 {
5005  return GetContentRegionAvail().x;
5006 }
5007 
5008 // In window space (not screen space!)
5010 {
5012  return window->ContentsRegionRect.Min;
5013 }
5014 
5016 {
5018  return window->ContentsRegionRect.Max;
5019 }
5020 
5022 {
5024  return window->ContentsRegionRect.Max.x - window->ContentsRegionRect.Min.x;
5025 }
5026 
5028 {
5029  ImGuiContext& g = *GImGui;
5030  return g.FontSize;
5031 }
5032 
5034 {
5035  ImGuiContext& g = *GImGui;
5036  return g.FontSize + g.Style.ItemSpacing.y;
5037 }
5038 
5040 {
5041  ImGuiContext& g = *GImGui;
5042  return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
5043 }
5044 
5046 {
5048  return window->DrawList;
5049 }
5050 
5052 {
5053  return GImGui->Font;
5054 }
5055 
5057 {
5058  return GImGui->FontSize;
5059 }
5060 
5062 {
5063  return GImGui->FontTexUvWhitePixel;
5064 }
5065 
5067 {
5068  ImGuiContext& g = *GImGui;
5070  window->FontWindowScale = scale;
5071  g.FontSize = window->CalcFontSize();
5072 }
5073 
5074 // User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
5075 // Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
5077 {
5079  return window->DC.CursorPos - window->Pos + window->Scroll;
5080 }
5081 
5083 {
5085  return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
5086 }
5087 
5089 {
5091  return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
5092 }
5093 
5094 void ImGui::SetCursorPos(const ImVec2& local_pos)
5095 {
5097  window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
5098  window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
5099 }
5100 
5102 {
5104  window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
5105  window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
5106 }
5107 
5109 {
5111  window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
5112  window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
5113 }
5114 
5116 {
5118  return window->DC.CursorStartPos - window->Pos;
5119 }
5120 
5122 {
5124  return window->DC.CursorPos;
5125 }
5126 
5127 void ImGui::SetCursorScreenPos(const ImVec2& screen_pos)
5128 {
5130  window->DC.CursorPos = screen_pos;
5131 }
5132 
5134 {
5135  return GImGui->CurrentWindow->Scroll.x;
5136 }
5137 
5139 {
5140  return GImGui->CurrentWindow->Scroll.y;
5141 }
5142 
5144 {
5146  return window->SizeContents.x - window->SizeFull.x - window->ScrollbarSizes.x;
5147 }
5148 
5150 {
5152  return window->SizeContents.y - window->SizeFull.y - window->ScrollbarSizes.y;
5153 }
5154 
5155 void ImGui::SetScrollX(float scroll_x)
5156 {
5158  window->ScrollTarget.x = scroll_x;
5159  window->ScrollTargetCenterRatio.x = 0.0f;
5160 }
5161 
5162 void ImGui::SetScrollY(float scroll_y)
5163 {
5165  window->ScrollTarget.y = scroll_y + window->TitleBarHeight(); // title bar height canceled out when using ScrollTargetRelY
5166  window->ScrollTargetCenterRatio.y = 0.0f;
5167 }
5168 
5169 void ImGui::SetScrollFromPosY(float pos_y, float center_y_ratio)
5170 {
5171  // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
5173  IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
5174  window->ScrollTarget.y = (float)(int)(pos_y + window->Scroll.y);
5175  if (center_y_ratio <= 0.0f && window->ScrollTarget.y <= window->WindowPadding.y) // Minor hack to make "scroll to top" take account of WindowPadding, else it would scroll to (WindowPadding.y - ItemSpacing.y)
5176  window->ScrollTarget.y = 0.0f;
5177  window->ScrollTargetCenterRatio.y = center_y_ratio;
5178 }
5179 
5180 // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
5181 void ImGui::SetScrollHere(float center_y_ratio)
5182 {
5184  float target_y = window->DC.CursorPosPrevLine.y + (window->DC.PrevLineHeight * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line.
5185  SetScrollFromPosY(target_y - window->Pos.y, center_y_ratio);
5186 }
5187 
5189 {
5191  window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset;
5192  window->FocusIdxTabRequestNext = INT_MAX;
5193 }
5194 
5196 {
5198  window->DC.StateStorage = tree ? tree : &window->StateStorage;
5199 }
5200 
5202 {
5204  return window->DC.StateStorage;
5205 }
5206 
5207 void ImGui::TextV(const char* fmt, va_list args)
5208 {
5210  if (window->SkipItems)
5211  return;
5212 
5213  ImGuiContext& g = *GImGui;
5214  const char* text_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
5215  TextUnformatted(g.TempBuffer, text_end);
5216 }
5217 
5218 void ImGui::Icon(const char* icon)
5219 {
5220  ImGui::Text("%s", icon);
5221 }
5222 
5223 void ImGui::Text(const char* fmt, ...)
5224 {
5225  va_list args;
5226  va_start(args, fmt);
5227  TextV(fmt, args);
5228  va_end(args);
5229 }
5230 
5231 void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)
5232 {
5234  TextV(fmt, args);
5235  PopStyleColor();
5236 }
5237 
5238 void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
5239 {
5240  va_list args;
5241  va_start(args, fmt);
5242  TextColoredV(col, fmt, args);
5243  va_end(args);
5244 }
5245 
5246 void ImGui::TextDisabledV(const char* fmt, va_list args)
5247 {
5249  TextV(fmt, args);
5250  PopStyleColor();
5251 }
5252 
5253 void ImGui::TextDisabled(const char* fmt, ...)
5254 {
5255  va_list args;
5256  va_start(args, fmt);
5257  TextDisabledV(fmt, args);
5258  va_end(args);
5259 }
5260 
5261 void ImGui::TextWrappedV(const char* fmt, va_list args)
5262 {
5263  PushTextWrapPos(0.0f);
5264  TextV(fmt, args);
5265  PopTextWrapPos();
5266 }
5267 
5268 void ImGui::TextWrapped(const char* fmt, ...)
5269 {
5270  va_list args;
5271  va_start(args, fmt);
5272  TextWrappedV(fmt, args);
5273  va_end(args);
5274 }
5275 
5276 void ImGui::TextUnformatted(const char* text, const char* text_end)
5277 {
5279  if (window->SkipItems)
5280  return;
5281 
5282  ImGuiContext& g = *GImGui;
5283  IM_ASSERT(text != NULL);
5284  const char* text_begin = text;
5285  if (text_end == NULL)
5286  text_end = text + strlen(text); // FIXME-OPT
5287 
5288  const float wrap_pos_x = window->DC.TextWrapPos;
5289  const bool wrap_enabled = wrap_pos_x >= 0.0f;
5290  if (text_end - text > 2000 && !wrap_enabled)
5291  {
5292  // Long text!
5293  // Perform manual coarse clipping to optimize for long multi-line text
5294  // From this point we will only compute the width of lines that are visible. Optimization only available when word-wrapping is disabled.
5295  // We also don't vertically center the text within the line full height, which is unlikely to matter because we are likely the biggest and only item on the line.
5296  const char* line = text;
5297  const float line_height = GetTextLineHeight();
5298  const ImVec2 text_pos = window->DC.CursorPos + ImVec2(0.0f, window->DC.CurrentLineTextBaseOffset);
5299  const ImRect clip_rect = window->ClipRect;
5300  ImVec2 text_size(0,0);
5301 
5302  if (text_pos.y <= clip_rect.Max.y)
5303  {
5304  ImVec2 pos = text_pos;
5305 
5306  // Lines to skip (can't skip when logging text)
5307  if (!g.LogEnabled)
5308  {
5309  int lines_skippable = (int)((clip_rect.Min.y - text_pos.y) / line_height);
5310  if (lines_skippable > 0)
5311  {
5312  int lines_skipped = 0;
5313  while (line < text_end && lines_skipped < lines_skippable)
5314  {
5315  const char* line_end = strchr(line, '\n');
5316  if (!line_end)
5317  line_end = text_end;
5318  line = line_end + 1;
5319  lines_skipped++;
5320  }
5321  pos.y += lines_skipped * line_height;
5322  }
5323  }
5324 
5325  // Lines to render
5326  if (line < text_end)
5327  {
5328  ImRect line_rect(pos, pos + ImVec2(GetWindowWidth(), line_height));
5329  while (line < text_end)
5330  {
5331  const char* line_end = strchr(line, '\n');
5332  if (IsClippedEx(line_rect, NULL, false))
5333  break;
5334 
5335  const ImVec2 line_size = CalcTextSize(line, line_end, false);
5336  text_size.x = ImMax(text_size.x, line_size.x);
5337  RenderText(pos, line, line_end, false);
5338  if (!line_end)
5339  line_end = text_end;
5340  line = line_end + 1;
5341  line_rect.Min.y += line_height;
5342  line_rect.Max.y += line_height;
5343  pos.y += line_height;
5344  }
5345 
5346  // Count remaining lines
5347  int lines_skipped = 0;
5348  while (line < text_end)
5349  {
5350  const char* line_end = strchr(line, '\n');
5351  if (!line_end)
5352  line_end = text_end;
5353  line = line_end + 1;
5354  lines_skipped++;
5355  }
5356  pos.y += lines_skipped * line_height;
5357  }
5358 
5359  text_size.y += (pos - text_pos).y;
5360  }
5361 
5362  ImRect bb(text_pos, text_pos + text_size);
5363  ItemSize(bb);
5364  ItemAdd(bb, NULL);
5365  }
5366  else
5367  {
5368  const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;
5369  const ImVec2 text_size = CalcTextSize(text_begin, text_end, false, wrap_width);
5370 
5371  // Account of baseline offset
5372  ImVec2 text_pos = window->DC.CursorPos;
5373  text_pos.y += window->DC.CurrentLineTextBaseOffset;
5374 
5375  ImRect bb(text_pos, text_pos + text_size);
5376  ItemSize(text_size);
5377  if (!ItemAdd(bb, NULL))
5378  return;
5379 
5380  // Render (we don't hide text after ## in this end-user function)
5381  RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width);
5382  }
5383 }
5384 
5386 {
5388  if (window->SkipItems)
5389  return;
5390 
5391  // Declare a dummy item size to that upcoming items that are smaller will center-align on the newly expanded line height.
5392  ImGuiContext& g = *GImGui;
5394  SameLine(0, 0);
5395 }
5396 
5397 // Add a label+text combo aligned to other label+value widgets
5398 void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
5399 {
5401  if (window->SkipItems)
5402  return;
5403 
5404  ImGuiContext& g = *GImGui;
5405  const ImGuiStyle& style = g.Style;
5406  const float w = CalcItemWidth();
5407 
5408  const ImVec2 label_size = CalcTextSize(label, NULL, true);
5409  const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2));
5410  const ImRect total_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x : 0.0f), style.FramePadding.y*2) + label_size);
5411  ItemSize(total_bb, style.FramePadding.y);
5412  if (!ItemAdd(total_bb, NULL))
5413  return;
5414 
5415  // Render
5416  const char* value_text_begin = &g.TempBuffer[0];
5417  const char* value_text_end = value_text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
5418  RenderTextClipped(value_bb.Min, value_bb.Max, value_text_begin, value_text_end, NULL, ImGuiAlign_VCenter);
5419  if (label_size.x > 0.0f)
5420  RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);
5421 }
5422 
5423 void ImGui::LabelText(const char* label, const char* fmt, ...)
5424 {
5425  va_list args;
5426  va_start(args, fmt);
5427  LabelTextV(label, fmt, args);
5428  va_end(args);
5429 }
5430 
5432 {
5433  // An active popup disable hovering on other windows (apart from its own children)
5434  ImGuiContext& g = *GImGui;
5435  if (ImGuiWindow* focused_window = g.FocusedWindow)
5436  if (ImGuiWindow* focused_root_window = focused_window->RootWindow)
5437  if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) != 0 && focused_root_window->WasActive && focused_root_window != window->RootWindow)
5438  return false;
5439 
5440  return true;
5441 }
5442 
5443 bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags)
5444 {
5445  ImGuiContext& g = *GImGui;
5447 
5448  if (flags & ImGuiButtonFlags_Disabled)
5449  {
5450  if (out_hovered) *out_hovered = false;
5451  if (out_held) *out_held = false;
5452  if (g.ActiveId == id) SetActiveID(0);
5453  return false;
5454  }
5455 
5458 
5459  bool pressed = false;
5460  bool hovered = IsHovered(bb, id, (flags & ImGuiButtonFlags_FlattenChilds) != 0);
5461  if (hovered)
5462  {
5463  SetHoveredID(id);
5464  if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!g.IO.KeyCtrl && !g.IO.KeyShift && !g.IO.KeyAlt))
5465  {
5466  // | CLICKING | HOLDING with ImGuiButtonFlags_Repeat
5467  // PressedOnClickRelease | <on release>* | <on repeat> <on repeat> .. (NOT on release) <-- MOST COMMON! (*) only if both click/release were over bounds
5468  // PressedOnClick | <on click> | <on click> <on repeat> <on repeat> ..
5469  // PressedOnRelease | <on release> | <on repeat> <on repeat> .. (NOT on release)
5470  // PressedOnDoubleClick | <on dclick> | <on dclick> <on repeat> <on repeat> ..
5472  {
5473  SetActiveID(id, window); // Hold on ID
5474  FocusWindow(window);
5475  g.ActiveIdClickOffset = g.IO.MousePos - bb.Min;
5476  }
5478  {
5479  pressed = true;
5480  SetActiveID(0);
5481  FocusWindow(window);
5482  }
5483  if ((flags & ImGuiButtonFlags_PressedOnRelease) && g.IO.MouseReleased[0])
5484  {
5485  if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release>
5486  pressed = true;
5487  SetActiveID(0);
5488  }
5489 
5490  // 'Repeat' mode acts when held regardless of _PressedOn flags (see table above).
5491  // Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings.
5492  if ((flags & ImGuiButtonFlags_Repeat) && g.ActiveId == id && g.IO.MouseDownDuration[0] > 0.0f && IsMouseClicked(0, true))
5493  pressed = true;
5494  }
5495  }
5496 
5497  bool held = false;
5498  if (g.ActiveId == id)
5499  {
5500  if (g.IO.MouseDown[0])
5501  {
5502  held = true;
5503  }
5504  else
5505  {
5506  if (hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease))
5507  if (!((flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[0] >= g.IO.KeyRepeatDelay)) // Repeat mode trumps <on release>
5508  pressed = true;
5509  SetActiveID(0);
5510  }
5511  }
5512 
5513  // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one.
5514  if (hovered && (flags & ImGuiButtonFlags_AllowOverlapMode) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0))
5515  hovered = pressed = held = false;
5516 
5517  if (out_hovered) *out_hovered = hovered;
5518  if (out_held) *out_held = held;
5519 
5520  return pressed;
5521 }
5522 
5523 bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags flags)
5524 {
5526  if (window->SkipItems)
5527  return false;
5528 
5529  ImGuiContext& g = *GImGui;
5530  const ImGuiStyle& style = g.Style;
5531  const ImGuiID id = window->GetID(label);
5532  const ImVec2 label_size = CalcTextSize(label, NULL, true);
5533 
5534  ImVec2 pos = window->DC.CursorPos;
5536  pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
5537  ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
5538 
5539  const ImRect bb(pos, pos + size);
5540  ItemSize(bb, style.FramePadding.y);
5541  if (!ItemAdd(bb, &id))
5542  return false;
5543 
5544  if (window->DC.ButtonRepeat) flags |= ImGuiButtonFlags_Repeat;
5545  bool hovered, held;
5546  bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
5547  bool button_disabled = flags & ImGuiButtonFlags_Disabled;
5548 
5549  // Render
5550  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
5551  RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
5552 
5553  if(button_disabled)
5554  PushStyleColor(ImGuiCol_Text, ImColor(GetColorU32({ 0.5f,0.5f,0.5f,1.f })));
5555 
5556  if (hovered || held)
5558 
5559  RenderTextClipped(bb.Min, bb.Max, label, NULL, &label_size, ImGuiAlign_Center | ImGuiAlign_VCenter);
5560  if (hovered || held)
5561  PopStyleColor();
5562 
5563  if (button_disabled)
5564  PopStyleColor();
5565 
5566  // Automatically close popups
5567  //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
5568  // CloseCurrentPopup();
5569 
5570  return pressed;
5571 }
5572 
5573 bool ImGui::Button(const char* label, const ImVec2& size_arg)
5574 {
5575  return ButtonEx(label, size_arg, 0);
5576 }
5577 
5578 // Small buttons fits within text without additional vertical spacing.
5579 bool ImGui::SmallButton(const char* label)
5580 {
5581  ImGuiContext& g = *GImGui;
5582  float backup_padding_y = g.Style.FramePadding.y;
5583  g.Style.FramePadding.y = 0.0f;
5584  bool pressed = ButtonEx(label, ImVec2(0,0), ImGuiButtonFlags_AlignTextBaseLine);
5585  g.Style.FramePadding.y = backup_padding_y;
5586  return pressed;
5587 }
5588 
5589 // Tip: use ImGui::PushID()/PopID() to push indices or pointers in the ID stack.
5590 // Then you can keep 'str_id' empty or the same for all your buttons (instead of creating a string based on a non-string id)
5591 bool ImGui::InvisibleButton(const char* str_id, const ImVec2& size_arg)
5592 {
5594  if (window->SkipItems)
5595  return false;
5596 
5597  const ImGuiID id = window->GetID(str_id);
5598  ImVec2 size = CalcItemSize(size_arg, 0.0f, 0.0f);
5599  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
5600  ItemSize(bb);
5601  if (!ItemAdd(bb, &id))
5602  return false;
5603 
5604  bool hovered, held;
5605  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
5606 
5607  return pressed;
5608 }
5609 
5610 // Upper-right button to close a window.
5611 bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
5612 {
5614 
5615  const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius));
5616 
5617  bool hovered, held;
5618  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
5619 
5620  // Render
5622  const ImVec2 center = bb.GetCenter();
5623  window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), col, 12);
5624 
5625  const float cross_extent = (radius * 0.7071f) - 1.0f;
5626  // if (hovered)
5627  // {
5628  window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), GetColorU32(ImGuiCol_Text));
5629  window->DrawList->AddLine(center + ImVec2(+cross_extent,-cross_extent), center + ImVec2(-cross_extent,+cross_extent), GetColorU32(ImGuiCol_Text));
5630 // }
5631 
5632  return pressed;
5633 }
5634 
5635 void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
5636 {
5638  if (window->SkipItems)
5639  return;
5640 
5641  ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
5642  if (border_col.w > 0.0f)
5643  bb.Max += ImVec2(2,2);
5644  ItemSize(bb);
5645  if (!ItemAdd(bb, NULL))
5646  return;
5647 
5648  if (border_col.w > 0.0f)
5649  {
5650  window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f);
5651  window->DrawList->AddImage(user_texture_id, bb.Min+ImVec2(1,1), bb.Max-ImVec2(1,1), uv0, uv1, GetColorU32(tint_col));
5652  }
5653  else
5654  {
5655  window->DrawList->AddImage(user_texture_id, bb.Min, bb.Max, uv0, uv1, GetColorU32(tint_col));
5656  }
5657 }
5658 
5659 // frame_padding < 0: uses FramePadding from style (default)
5660 // frame_padding = 0: no framing
5661 // frame_padding > 0: set framing size
5662 // The color used are the button colors.
5663 bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)
5664 {
5666  if (window->SkipItems)
5667  return false;
5668 
5669  ImGuiContext& g = *GImGui;
5670  const ImGuiStyle& style = g.Style;
5671 
5672  // Default to using texture ID as ID. User can still push string/integer prefixes.
5673  // We could hash the size/uv to create a unique ID but that would prevent the user from animating UV.
5674  PushID((void *)user_texture_id);
5675  const ImGuiID id = window->GetID("#image");
5676  PopID();
5677 
5678  const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : style.FramePadding;
5679  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding*2);
5680  const ImRect image_bb(window->DC.CursorPos + padding, window->DC.CursorPos + padding + size);
5681  ItemSize(bb);
5682  if (!ItemAdd(bb, &id))
5683  return false;
5684 
5685  bool hovered, held;
5686  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
5687 
5688  // Render
5689  const ImU32 col = GetColorU32((hovered && held) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
5690  RenderFrame(bb.Min, bb.Max, col, true, ImClamp((float)ImMin(padding.x, padding.y), 0.0f, style.FrameRounding));
5691  if (bg_col.w > 0.0f)
5692  window->DrawList->AddRectFilled(image_bb.Min, image_bb.Max, GetColorU32(bg_col));
5693  window->DrawList->AddImage(user_texture_id, image_bb.Min, image_bb.Max, uv0, uv1, GetColorU32(tint_col));
5694 
5695  return pressed;
5696 }
5697 
5698 // Start logging ImGui output to TTY
5699 void ImGui::LogToTTY(int max_depth)
5700 {
5701  ImGuiContext& g = *GImGui;
5702  if (g.LogEnabled)
5703  return;
5705 
5706  g.LogEnabled = true;
5707  g.LogFile = stdout;
5708  g.LogStartDepth = window->DC.TreeDepth;
5709  if (max_depth >= 0)
5710  g.LogAutoExpandMaxDepth = max_depth;
5711 }
5712 
5713 // Start logging ImGui output to given file
5714 void ImGui::LogToFile(int max_depth, const char* filename)
5715 {
5716  ImGuiContext& g = *GImGui;
5717  if (g.LogEnabled)
5718  return;
5720 
5721  if (!filename)
5722  {
5723  filename = g.IO.LogFilename;
5724  if (!filename)
5725  return;
5726  }
5727 
5728  g.LogFile = fopen(filename, "ab");
5729  if (!g.LogFile)
5730  {
5731  IM_ASSERT(g.LogFile != NULL); // Consider this an error
5732  return;
5733  }
5734  g.LogEnabled = true;
5735  g.LogStartDepth = window->DC.TreeDepth;
5736  if (max_depth >= 0)
5737  g.LogAutoExpandMaxDepth = max_depth;
5738 }
5739 
5740 // Start logging ImGui output to clipboard
5741 void ImGui::LogToClipboard(int max_depth)
5742 {
5743  ImGuiContext& g = *GImGui;
5744  if (g.LogEnabled)
5745  return;
5747 
5748  g.LogEnabled = true;
5749  g.LogFile = NULL;
5750  g.LogStartDepth = window->DC.TreeDepth;
5751  if (max_depth >= 0)
5752  g.LogAutoExpandMaxDepth = max_depth;
5753 }
5754 
5756 {
5757  ImGuiContext& g = *GImGui;
5758  if (!g.LogEnabled)
5759  return;
5760 
5762  g.LogEnabled = false;
5763  if (g.LogFile != NULL)
5764  {
5765  if (g.LogFile == stdout)
5766  fflush(g.LogFile);
5767  else
5768  fclose(g.LogFile);
5769  g.LogFile = NULL;
5770  }
5771  if (g.LogClipboard->size() > 1)
5772  {
5773  if (g.IO.SetClipboardTextFn)
5775  g.LogClipboard->clear();
5776  }
5777 }
5778 
5779 // Helper to display logging buttons
5781 {
5782  ImGuiContext& g = *GImGui;
5783 
5784  PushID("LogButtons");
5785  const bool log_to_tty = Button("Log To TTY"); SameLine();
5786  const bool log_to_file = Button("Log To File"); SameLine();
5787  const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
5788  PushItemWidth(80.0f);
5789  PushAllowKeyboardFocus(false);
5790  SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL);
5792  PopItemWidth();
5793  PopID();
5794 
5795  // Start logging at the end of the function so that the buttons don't appear in the log
5796  if (log_to_tty)
5798  if (log_to_file)
5800  if (log_to_clipboard)
5802 }
5803 
5805 {
5806  if (flags & ImGuiTreeNodeFlags_Leaf)
5807  return true;
5808 
5809  // We only write to the tree storage if the user clicks (or explicitely use SetNextTreeNode*** functions)
5810  ImGuiContext& g = *GImGui;
5812  ImGuiStorage* storage = window->DC.StateStorage;
5813 
5814  bool is_open;
5815  if (g.SetNextTreeNodeOpenCond != 0)
5816  {
5818  {
5819  is_open = g.SetNextTreeNodeOpenVal;
5820  storage->SetInt(id, is_open);
5821  }
5822  else
5823  {
5824  // We treat ImGuiSetCondition_Once and ImGuiSetCondition_FirstUseEver the same because tree node state are not saved persistently.
5825  const int stored_value = storage->GetInt(id, -1);
5826  if (stored_value == -1)
5827  {
5828  is_open = g.SetNextTreeNodeOpenVal;
5829  storage->SetInt(id, is_open);
5830  }
5831  else
5832  {
5833  is_open = stored_value != 0;
5834  }
5835  }
5837  }
5838  else
5839  {
5840  is_open = storage->GetInt(id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;
5841  }
5842 
5843  // When logging is enabled, we automatically expand tree nodes (but *NOT* collapsing headers.. seems like sensible behavior).
5844  // NB- If we are above max depth we still allow manually opened nodes to be logged.
5846  is_open = true;
5847 
5848  return is_open;
5849 }
5850 
5851 bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end)
5852 {
5854  if (window->SkipItems)
5855  return false;
5856 
5857  ImGuiContext& g = *GImGui;
5858  const ImGuiStyle& style = g.Style;
5859  const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
5860  const ImVec2 padding = display_frame ? style.FramePadding : ImVec2(style.FramePadding.x, style.FramePadding.y);
5861 
5862  if (!label_end)
5863  label_end = FindRenderedTextEnd(label);
5864  const ImVec2 label_size = CalcTextSize(label, label_end, false);
5865 
5866  // We vertically grow up to current line height up the typical widget height.
5867  const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset - padding.y); // Latch before ItemSize changes it
5868  const float frame_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2);
5869  ImRect bb = ImRect(window->DC.CursorPos, ImVec2(window->Pos.x + GetContentRegionMax().x, window->DC.CursorPos.y + frame_height));
5870  if (display_frame)
5871  {
5872  // Framed header expand a little outside the default padding
5873  bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1;
5874  bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1;
5875  }
5876 
5877  const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing
5878  const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser
5879  ItemSize(ImVec2(text_width, frame_height), text_base_offset_y);
5880 
5881  // For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
5882  // (Ideally we'd want to add a flag for the user to specify we want want the hit test to be done up to the right side of the content or not)
5883  const ImRect interact_bb = display_frame ? bb : ImRect(bb.Min.x, bb.Min.y, bb.Min.x + text_width + style.ItemSpacing.x*2, bb.Max.y);
5884  bool is_open = TreeNodeBehaviorIsOpen(id, flags);
5885  if (!ItemAdd(interact_bb, &id))
5886  {
5887  if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
5888  TreePushRawID(id);
5889  return is_open;
5890  }
5891 
5892  // Flags that affects opening behavior:
5893  // - 0(default) ..................... single-click anywhere to open
5894  // - OpenOnDoubleClick .............. double-click anywhere to open
5895  // - OpenOnArrow .................... single-click on arrow to open
5896  // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
5900  bool hovered, held, pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
5901  if (pressed && !(flags & ImGuiTreeNodeFlags_Leaf))
5902  {
5904  if (flags & ImGuiTreeNodeFlags_OpenOnArrow)
5905  toggled |= IsMouseHoveringRect(interact_bb.Min, ImVec2(interact_bb.Min.x + text_offset_x, interact_bb.Max.y));
5906  if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
5907  toggled |= g.IO.MouseDoubleClicked[0];
5908  if (toggled)
5909  {
5910  is_open = !is_open;
5911  window->DC.StateStorage->SetInt(id, is_open);
5912  }
5913  }
5916 
5917  // Render
5918  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
5919  const ImVec2 text_pos = bb.Min + ImVec2(text_offset_x, padding.y + text_base_offset_y);
5920  if (display_frame)
5921  {
5922  // Framed type
5923  RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
5924  RenderCollapseTriangle(bb.Min + padding + ImVec2(0.0f, text_base_offset_y), is_open, 1.0f, true);
5925  if (g.LogEnabled)
5926  {
5927  // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here.
5928  const char log_prefix[] = "\n##";
5929  const char log_suffix[] = "##";
5930  LogRenderedText(text_pos, log_prefix, log_prefix+3);
5931  RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size);
5932  LogRenderedText(text_pos, log_suffix+1, log_suffix+3);
5933  }
5934  else
5935  {
5936  RenderTextClipped(text_pos, bb.Max, label, label_end, &label_size);
5937  }
5938  }
5939  else
5940  {
5941  // Unframed typed for tree nodes
5942  if (hovered || (flags & ImGuiTreeNodeFlags_Selected))
5943  RenderFrame(bb.Min, bb.Max, col, false);
5944 
5945  if (flags & ImGuiTreeNodeFlags_Bullet)
5946  RenderBullet(bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y));
5947  else if (!(flags & ImGuiTreeNodeFlags_Leaf))
5948  RenderCollapseTriangle(bb.Min + ImVec2(padding.x, padding.y + g.FontSize*0.15f + text_base_offset_y), is_open, 0.70f, false);
5949  if (g.LogEnabled)
5950  LogRenderedText(text_pos, ">");
5951  RenderText(text_pos, label, label_end, false);
5952  }
5953 
5954  if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
5955  TreePushRawID(id);
5956  return is_open;
5957 }
5958 
5959 // CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag).
5960 // This is basically the same as calling TreeNodeEx(label, ImGuiTreeNodeFlags_CollapsingHeader | ImGuiTreeNodeFlags_NoTreePushOnOpen). You can remove the _NoTreePushOnOpen flag if you want behavior closer to normal TreeNode().
5962 {
5964  if (window->SkipItems)
5965  return false;
5966 
5968 }
5969 
5970 bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags)
5971 {
5973  if (window->SkipItems)
5974  return false;
5975 
5976  if (p_open && !*p_open)
5977  return false;
5978 
5979  ImGuiID id = window->GetID(label);
5981  if (p_open)
5982  {
5983  // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
5984  ImGuiContext& g = *GImGui;
5985  float button_sz = g.FontSize * 0.5f;
5986  if (CloseButton(window->GetID((void*)(intptr_t)(id+1)), ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_sz, window->DC.LastItemRect.Min.y + g.Style.FramePadding.y + button_sz), button_sz))
5987  *p_open = false;
5988  }
5989 
5990  return is_open;
5991 }
5992 
5994 {
5996  if (window->SkipItems)
5997  return false;
5998 
5999  return TreeNodeBehavior(window->GetID(label), flags, label, NULL);
6000 }
6001 
6002 bool ImGui::TreeNodeExV(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
6003 {
6005  if (window->SkipItems)
6006  return false;
6007 
6008  ImGuiContext& g = *GImGui;
6009  const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
6010  return TreeNodeBehavior(window->GetID(str_id), flags, g.TempBuffer, label_end);
6011 }
6012 
6013 bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, va_list args)
6014 {
6016  if (window->SkipItems)
6017  return false;
6018 
6019  ImGuiContext& g = *GImGui;
6020  const char* label_end = g.TempBuffer + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
6021  return TreeNodeBehavior(window->GetID(ptr_id), flags, g.TempBuffer, label_end);
6022 }
6023 
6024 bool ImGui::TreeNodeV(const char* str_id, const char* fmt, va_list args)
6025 {
6026  return TreeNodeExV(str_id, 0, fmt, args);
6027 }
6028 
6029 bool ImGui::TreeNodeV(const void* ptr_id, const char* fmt, va_list args)
6030 {
6031  return TreeNodeExV(ptr_id, 0, fmt, args);
6032 }
6033 
6034 bool ImGui::TreeNodeEx(const char* str_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
6035 {
6036  va_list args;
6037  va_start(args, fmt);
6038  bool is_open = TreeNodeExV(str_id, flags, fmt, args);
6039  va_end(args);
6040  return is_open;
6041 }
6042 
6043 bool ImGui::TreeNodeEx(const void* ptr_id, ImGuiTreeNodeFlags flags, const char* fmt, ...)
6044 {
6045  va_list args;
6046  va_start(args, fmt);
6047  bool is_open = TreeNodeExV(ptr_id, flags, fmt, args);
6048  va_end(args);
6049  return is_open;
6050 }
6051 
6052 bool ImGui::TreeNode(const char* str_id, const char* fmt, ...)
6053 {
6054  va_list args;
6055  va_start(args, fmt);
6056  bool is_open = TreeNodeExV(str_id, 0, fmt, args);
6057  va_end(args);
6058  return is_open;
6059 }
6060 
6061 bool ImGui::TreeNode(const void* ptr_id, const char* fmt, ...)
6062 {
6063  va_list args;
6064  va_start(args, fmt);
6065  bool is_open = TreeNodeExV(ptr_id, 0, fmt, args);
6066  va_end(args);
6067  return is_open;
6068 }
6069 
6070 bool ImGui::TreeNode(const char* label)
6071 {
6073  if (window->SkipItems)
6074  return false;
6075  return TreeNodeBehavior(window->GetID(label), 0, label, NULL);
6076 }
6077 
6079 {
6080  ImGuiContext& g = *GImGui;
6082 }
6083 
6084 // Horizontal distance preceeding label when using TreeNode() or Bullet()
6086 {
6087  ImGuiContext& g = *GImGui;
6088  return g.FontSize + (g.Style.FramePadding.x * 2.0f);
6089 }
6090 
6092 {
6093  ImGuiContext& g = *GImGui;
6094  g.SetNextTreeNodeOpenVal = is_open;
6095  g.SetNextTreeNodeOpenCond = cond ? cond : ImGuiSetCond_Always;
6096 }
6097 
6098 void ImGui::PushID(const char* str_id)
6099 {
6101  window->IDStack.push_back(window->GetID(str_id));
6102 }
6103 
6104 void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
6105 {
6107  window->IDStack.push_back(window->GetID(str_id_begin, str_id_end));
6108 }
6109 
6110 void ImGui::PushID(const void* ptr_id)
6111 {
6113  window->IDStack.push_back(window->GetID(ptr_id));
6114 }
6115 
6116 void ImGui::PushID(int int_id)
6117 {
6118  const void* ptr_id = (void*)(intptr_t)int_id;
6120  window->IDStack.push_back(window->GetID(ptr_id));
6121 }
6122 
6124 {
6126  window->IDStack.pop_back();
6127 }
6128 
6129 ImGuiID ImGui::GetID(const char* str_id)
6130 {
6131  return GImGui->CurrentWindow->GetID(str_id);
6132 }
6133 
6134 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
6135 {
6136  return GImGui->CurrentWindow->GetID(str_id_begin, str_id_end);
6137 }
6138 
6139 ImGuiID ImGui::GetID(const void* ptr_id)
6140 {
6141  return GImGui->CurrentWindow->GetID(ptr_id);
6142 }
6143 
6145 {
6147  if (window->SkipItems)
6148  return;
6149 
6150  ImGuiContext& g = *GImGui;
6151  const ImGuiStyle& style = g.Style;
6152  const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
6153  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height));
6154  ItemSize(bb);
6155  if (!ItemAdd(bb, NULL))
6156  {
6157  SameLine(0, style.FramePadding.x*2);
6158  return;
6159  }
6160 
6161  // Render and stay on same line
6162  RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
6163  SameLine(0, style.FramePadding.x*2);
6164 }
6165 
6166 // Text with a little bullet aligned to the typical tree node.
6167 void ImGui::BulletTextV(const char* fmt, va_list args)
6168 {
6170  if (window->SkipItems)
6171  return;
6172 
6173  ImGuiContext& g = *GImGui;
6174  const ImGuiStyle& style = g.Style;
6175 
6176  const char* text_begin = g.TempBuffer;
6177  const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
6178  const ImVec2 label_size = CalcTextSize(text_begin, text_end, true);
6179  const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
6180  const float line_height = ImMax(ImMin(window->DC.CurrentLineHeight, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
6181  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding
6182  ItemSize(bb);
6183  if (!ItemAdd(bb, NULL))
6184  return;
6185 
6186  // Render
6187  RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
6188  RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end);
6189 }
6190 
6191 void ImGui::BulletText(const char* fmt, ...)
6192 {
6193  va_list args;
6194  va_start(args, fmt);
6195  BulletTextV(fmt, args);
6196  va_end(args);
6197 }
6198 
6199 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, const char* display_format, char* buf, int buf_size)
6200 {
6201  if (data_type == ImGuiDataType_Int)
6202  ImFormatString(buf, buf_size, display_format, *(int*)data_ptr);
6203  else if (data_type == ImGuiDataType_Float)
6204  ImFormatString(buf, buf_size, display_format, *(float*)data_ptr);
6205 }
6206 
6207 static inline void DataTypeFormatString(ImGuiDataType data_type, void* data_ptr, int decimal_precision, char* buf, int buf_size)
6208 {
6209  if (data_type == ImGuiDataType_Int)
6210  {
6211  if (decimal_precision < 0)
6212  ImFormatString(buf, buf_size, "%d", *(int*)data_ptr);
6213  else
6214  ImFormatString(buf, buf_size, "%.*d", decimal_precision, *(int*)data_ptr);
6215  }
6216  else if (data_type == ImGuiDataType_Float)
6217  {
6218  if (decimal_precision < 0)
6219  ImFormatString(buf, buf_size, "%f", *(float*)data_ptr); // Ideally we'd have a minimum decimal precision of 1 to visually denote that it is a float, while hiding non-significant digits?
6220  else
6221  ImFormatString(buf, buf_size, "%.*f", decimal_precision, *(float*)data_ptr);
6222  }
6223 }
6224 
6225 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* value1, const void* value2)// Store into value1
6226 {
6227  if (data_type == ImGuiDataType_Int)
6228  {
6229  if (op == '+')
6230  *(int*)value1 = *(int*)value1 + *(const int*)value2;
6231  else if (op == '-')
6232  *(int*)value1 = *(int*)value1 - *(const int*)value2;
6233  }
6234  else if (data_type == ImGuiDataType_Float)
6235  {
6236  if (op == '+')
6237  *(float*)value1 = *(float*)value1 + *(const float*)value2;
6238  else if (op == '-')
6239  *(float*)value1 = *(float*)value1 - *(const float*)value2;
6240  }
6241 }
6242 
6243 // User can input math operators (e.g. +100) to edit a numerical values.
6244 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* scalar_format)
6245 {
6246  while (ImCharIsSpace(*buf))
6247  buf++;
6248 
6249  // We don't support '-' op because it would conflict with inputing negative value.
6250  // Instead you can use +-100 to subtract from an existing value
6251  char op = buf[0];
6252  if (op == '+' || op == '*' || op == '/')
6253  {
6254  buf++;
6255  while (ImCharIsSpace(*buf))
6256  buf++;
6257  }
6258  else
6259  {
6260  op = 0;
6261  }
6262  if (!buf[0])
6263  return false;
6264 
6265  if (data_type == ImGuiDataType_Int)
6266  {
6267  if (!scalar_format)
6268  scalar_format = "%d";
6269  int* v = (int*)data_ptr;
6270  const int old_v = *v;
6271  int arg0 = *v;
6272  if (op && sscanf(initial_value_buf, scalar_format, &arg0) < 1)
6273  return false;
6274 
6275  // Store operand in a float so we can use fractional value for multipliers (*1.1), but constant always parsed as integer so we can fit big integers (e.g. 2000000003) past float precision
6276  float arg1 = 0.0f;
6277  if (op == '+') { if (sscanf(buf, "%f", &arg1) == 1) *v = (int)(arg0 + arg1); } // Add (use "+-" to subtract)
6278  else if (op == '*') { if (sscanf(buf, "%f", &arg1) == 1) *v = (int)(arg0 * arg1); } // Multiply
6279  else if (op == '/') { if (sscanf(buf, "%f", &arg1) == 1 && arg1 != 0.0f) *v = (int)(arg0 / arg1); }// Divide
6280  else { if (sscanf(buf, scalar_format, &arg0) == 1) *v = arg0; } // Assign constant
6281  return (old_v != *v);
6282  }
6283  else if (data_type == ImGuiDataType_Float)
6284  {
6285  // For floats we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in
6286  scalar_format = "%f";
6287  float* v = (float*)data_ptr;
6288  const float old_v = *v;
6289  float arg0 = *v;
6290  if (op && sscanf(initial_value_buf, scalar_format, &arg0) < 1)
6291  return false;
6292 
6293  float arg1 = 0.0f;
6294  if (sscanf(buf, scalar_format, &arg1) < 1)
6295  return false;
6296  if (op == '+') { *v = arg0 + arg1; } // Add (use "+-" to subtract)
6297  else if (op == '*') { *v = arg0 * arg1; } // Multiply
6298  else if (op == '/') { if (arg1 != 0.0f) *v = arg0 / arg1; } // Divide
6299  else { *v = arg1; } // Assign constant
6300  return (old_v != *v);
6301  }
6302 
6303  return false;
6304 }
6305 
6306 // Create text input in place of a slider (when CTRL+Clicking on slider)
6307 bool ImGui::InputScalarAsWidgetReplacement(const ImRect& aabb, const char* label, ImGuiDataType data_type, void* data_ptr, ImGuiID id, int decimal_precision)
6308 {
6309  ImGuiContext& g = *GImGui;
6311 
6312  // Our replacement widget will override the focus ID (registered previously to allow for a TAB focus to happen)
6313  SetActiveID(g.ScalarAsInputTextId, window);
6314  SetHoveredID(0);
6315  FocusableItemUnregister(window);
6316 
6317  char buf[32];
6318  DataTypeFormatString(data_type, data_ptr, decimal_precision, buf, IM_ARRAYSIZE(buf));
6319  bool text_value_changed = InputTextEx(label, buf, IM_ARRAYSIZE(buf), aabb.GetSize(), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll);
6320  if (g.ScalarAsInputTextId == 0)
6321  {
6322  // First frame
6323  IM_ASSERT(g.ActiveId == id); // InputText ID expected to match the Slider ID (else we'd need to store them both, which is also possible)
6325  SetHoveredID(id);
6326  }
6327  else if (g.ActiveId != g.ScalarAsInputTextId)
6328  {
6329  // Release
6330  g.ScalarAsInputTextId = 0;
6331  }
6332  if (text_value_changed)
6333  return DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, NULL);
6334  return false;
6335 }
6336 
6337 // Parse display precision back from the display format string
6338 int ImGui::ParseFormatPrecision(const char* fmt, int default_precision)
6339 {
6340  int precision = default_precision;
6341  while ((fmt = strchr(fmt, '%')) != NULL)
6342  {
6343  fmt++;
6344  if (fmt[0] == '%') { fmt++; continue; } // Ignore "%%"
6345  while (*fmt >= '0' && *fmt <= '9')
6346  fmt++;
6347  if (*fmt == '.')
6348  {
6349  precision = atoi(fmt + 1);
6351  precision = default_precision;
6352  }
6353  break;
6354  }
6355  return precision;
6356 }
6357 
6358 float ImGui::RoundScalar(float value, int decimal_precision)
6359 {
6360  // Round past decimal precision
6361  // So when our value is 1.99999 with a precision of 0.001 we'll end up rounding to 2.0
6362  // FIXME: Investigate better rounding methods
6363  static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f };
6364  float min_step = (decimal_precision >= 0 && decimal_precision < 10) ? min_steps[decimal_precision] : powf(10.0f, (float)-decimal_precision);
6365  bool negative = value < 0.0f;
6366  value = fabsf(value);
6367  float remainder = fmodf(value, min_step);
6368  if (remainder <= min_step*0.5f)
6369  value -= remainder;
6370  else
6371  value += (min_step - remainder);
6372  return negative ? -value : value;
6373 }
6374 
6375 bool ImGui::SliderBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags, bool render_bg)
6376 {
6377  ImGuiContext& g = *GImGui;
6379  const ImGuiStyle& style = g.Style;
6380 
6381  const bool is_non_linear = fabsf(power - 1.0f) > 0.0001f;
6382  const bool is_horizontal = (flags & ImGuiSliderFlags_Vertical) == 0;
6383 
6384 
6385  if (!render_bg)
6386  {
6387  // Draw frame
6388  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
6389  }
6390 
6391 
6392  const float grab_padding = 2.0f;
6393  const float slider_sz = is_horizontal ? (frame_bb.GetWidth() - grab_padding * 2.0f) : (frame_bb.GetHeight() - grab_padding * 2.0f);
6394  float grab_sz;
6395  if (decimal_precision > 0)
6396  grab_sz = ImMin(style.GrabMinSize, slider_sz);
6397  else
6398  grab_sz = ImMin(ImMax(1.0f * (slider_sz / (v_max-v_min+1.0f)), style.GrabMinSize), slider_sz); // Integer sliders, if possible have the grab size represent 1 unit
6399  const float slider_usable_sz = slider_sz - grab_sz;
6400  const float slider_usable_pos_min = (is_horizontal ? frame_bb.Min.x : frame_bb.Min.y) + grab_padding + grab_sz*0.5f;
6401  const float slider_usable_pos_max = (is_horizontal ? frame_bb.Max.x : frame_bb.Max.y) - grab_padding - grab_sz*0.5f;
6402 
6403  // For logarithmic sliders that cross over sign boundary we want the exponential increase to be symmetric around 0.0f
6404  float linear_zero_pos = 0.0f; // 0.0->1.0f
6405  if (v_min * v_max < 0.0f)
6406  {
6407  // Different sign
6408  const float linear_dist_min_to_0 = powf(fabsf(0.0f - v_min), 1.0f/power);
6409  const float linear_dist_max_to_0 = powf(fabsf(v_max - 0.0f), 1.0f/power);
6410  linear_zero_pos = linear_dist_min_to_0 / (linear_dist_min_to_0+linear_dist_max_to_0);
6411  }
6412  else
6413  {
6414  // Same sign
6415  linear_zero_pos = v_min < 0.0f ? 1.0f : 0.0f;
6416  }
6417 
6418  // Process clicking on the slider
6419  bool value_changed = false;
6420  if (g.ActiveId == id)
6421  {
6422  if (g.IO.MouseDown[0])
6423  {
6424  const float mouse_abs_pos = is_horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
6425  float normalized_pos = ImClamp((mouse_abs_pos - slider_usable_pos_min) / slider_usable_sz, 0.0f, 1.0f);
6426  if (!is_horizontal)
6427  normalized_pos = 1.0f - normalized_pos;
6428 
6429  float new_value;
6430  if (is_non_linear)
6431  {
6432  // Account for logarithmic scale on both sides of the zero
6433  if (normalized_pos < linear_zero_pos)
6434  {
6435  // Negative: rescale to the negative range before powering
6436  float a = 1.0f - (normalized_pos / linear_zero_pos);
6437  a = powf(a, power);
6438  new_value = ImLerp(ImMin(v_max,0.0f), v_min, a);
6439  }
6440  else
6441  {
6442  // Positive: rescale to the positive range before powering
6443  float a;
6444  if (fabsf(linear_zero_pos - 1.0f) > 1.e-6f)
6445  a = (normalized_pos - linear_zero_pos) / (1.0f - linear_zero_pos);
6446  else
6447  a = normalized_pos;
6448  a = powf(a, power);
6449  new_value = ImLerp(ImMax(v_min,0.0f), v_max, a);
6450  }
6451  }
6452  else
6453  {
6454  // Linear slider
6455  new_value = ImLerp(v_min, v_max, normalized_pos);
6456  }
6457 
6458  // Round past decimal precision
6459  new_value = RoundScalar(new_value, decimal_precision);
6460  if (*v != new_value)
6461  {
6462  *v = new_value;
6463  value_changed = true;
6464  }
6465  }
6466  else
6467  {
6468  SetActiveID(0);
6469  }
6470  }
6471 
6472  // Calculate slider grab positioning
6473  float grab_t;
6474  if (is_non_linear)
6475  {
6476  float v_clamped = ImClamp(*v, v_min, v_max);
6477  if (v_clamped < 0.0f)
6478  {
6479  const float f = 1.0f - (v_clamped - v_min) / (ImMin(0.0f,v_max) - v_min);
6480  grab_t = (1.0f - powf(f, 1.0f/power)) * linear_zero_pos;
6481  }
6482  else
6483  {
6484  const float f = (v_clamped - ImMax(0.0f,v_min)) / (v_max - ImMax(0.0f,v_min));
6485  grab_t = linear_zero_pos + powf(f, 1.0f/power) * (1.0f - linear_zero_pos);
6486  }
6487  }
6488  else
6489  {
6490  // Linear slider
6491  grab_t = (ImClamp(*v, v_min, v_max) - v_min) / (v_max - v_min);
6492  }
6493 
6494  // Draw
6495  if (!is_horizontal)
6496  grab_t = 1.0f - grab_t;
6497  const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
6498  ImRect grab_bb;
6499  if (is_horizontal)
6500  grab_bb = ImRect(ImVec2(grab_pos - grab_sz*0.5f, frame_bb.Min.y + grab_padding), ImVec2(grab_pos + grab_sz*0.5f, frame_bb.Max.y - grab_padding));
6501  else
6502  grab_bb = ImRect(ImVec2(frame_bb.Min.x + grab_padding, grab_pos - grab_sz*0.5f), ImVec2(frame_bb.Max.x - grab_padding, grab_pos + grab_sz*0.5f));
6503 
6504  if(render_bg)
6505  {
6506  auto bb = frame_bb;
6507  ImRect fill_br = frame_bb;
6508  auto slider_height = bb.Max.y - bb.Min.y;
6509  auto slider_width = bb.Max.x - bb.Min.x;
6510  ImVec2 graber_size = {};
6511  float width = (grab_bb.Max.x - grab_bb.Min.x);
6512  float height = (grab_bb.Max.y - grab_bb.Min.y);
6513  float radius = 1.0;
6514  if (is_horizontal)
6515  {
6516  bb.Min.y = bb.Min.y + (slider_height / 3);
6517  bb.Max.y = bb.Max.y - (slider_height / 3);
6518  if (bb.Max.y - bb.Min.y < 1.0f)
6519  {
6520  bb.Min.y -= 0.5;
6521  bb.Max.y += 0.5;
6522  }
6523  float grab_paddingl = 2.0f;
6524  //Horizontal fills from left to right
6525  fill_br.Min = bb.Min;
6526  fill_br.Max = ImVec2(ImLerp(bb.Min.x, bb.Max.x - grab_paddingl, *v / 100), bb.Max.y);
6527  graber_size = { grab_bb.Max.x - (width / 2.0f) , grab_bb.Max.y - (height / 2.0f) };
6528  radius = height / 2.5f;
6529  }
6530  else
6531  {
6532  bb.Min.x = bb.Min.x + (slider_width / 3);
6533  bb.Max.x = bb.Max.x - (slider_width / 3);
6534  if (bb.Max.x - bb.Min.x < 1.0f)
6535  {
6536  bb.Min.x -= 0.5;
6537  bb.Max.x += 0.5;
6538  }
6539  //Vertical fills from down upwards
6540  fill_br.Min = bb.Min;
6541  fill_br.Min.y = grab_bb.Min.y;
6542  fill_br.Max = bb.Max;
6543  graber_size = { grab_bb.Max.x - (width / 2.0f) , grab_bb.Max.y - (height / 2.0f) };
6544  radius = width;// / 2.5;
6545  }
6546  // Draw frame
6547  RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), false, 10.0f);
6548  RenderFrame(fill_br.Min, fill_br.Max, ImGui::ColorConvertFloat4ToU32({ 0, 112.f / 255, 197.f / 255, 1 }), false, 10.0f);
6549  window->DrawList->AddCircleFilled(graber_size, radius, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), 16);
6550  }
6551  else
6552  {
6554  }
6555 
6556  return value_changed;
6557 }
6558 
6559 bool ImGui::SeekSlider(const char* label, int* v, const char* display_format)
6560 {
6561  return SliderInt(label, v, 0, 100, display_format,true);
6562 }
6563 
6564 // Use power!=1.0 for logarithmic sliders.
6565 // Adjust display_format to decorate the value with a prefix or a suffix.
6566 // "%.3f" 1.234
6567 // "%5.2f secs" 01.23 secs
6568 // "Gold: %.0f" Gold: 1
6569 //bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format, float power)
6570 bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, const char* display_format, float power, bool render_bg)
6571 {
6573  if (window->SkipItems)
6574  return false;
6575 
6576  ImGuiContext& g = *GImGui;
6577  const ImGuiStyle& style = g.Style;
6578  const ImGuiID id = window->GetID(label);
6579  const float w = CalcItemWidth();
6580 
6581  const ImVec2 label_size = CalcTextSize(label, NULL, true);
6582  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
6583  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
6584 
6585  // NB- we don't call ItemSize() yet because we may turn into a text edit box below
6586  if (!ItemAdd(total_bb, &id))
6587  {
6588  ItemSize(total_bb, style.FramePadding.y);
6589  return false;
6590  }
6591 
6592  const bool hovered = IsHovered(frame_bb, id);
6593  if (hovered)
6594  SetHoveredID(id);
6595 
6596  if (!display_format)
6597  display_format = "%.3f";
6598  int decimal_precision = ParseFormatPrecision(display_format, 3);
6599 
6600  // Tabbing or CTRL-clicking on Slider turns it into an input box
6601  bool start_text_input = false;
6602  const bool tab_focus_requested = FocusableItemRegister(window, g.ActiveId == id);
6603  if (tab_focus_requested || (hovered && g.IO.MouseClicked[0]))
6604  {
6605  SetActiveID(id, window);
6606  FocusWindow(window);
6607 
6608  if (tab_focus_requested || g.IO.KeyCtrl)
6609  {
6610  start_text_input = true;
6611  g.ScalarAsInputTextId = 0;
6612  }
6613  }
6614  if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
6615  return InputScalarAsWidgetReplacement(frame_bb, label, ImGuiDataType_Float, v, id, decimal_precision);
6616 
6617  ItemSize(total_bb, style.FramePadding.y);
6618 
6619  // Actual slider behavior + render grab
6620  const bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, power, decimal_precision, 0, render_bg);
6621 
6622  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
6623  char value_buf[64];
6624  const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
6625  RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center|ImGuiAlign_VCenter);
6626 
6627  if (label_size.x > 0.0f)
6628  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
6629 
6630  return value_changed;
6631 }
6632 
6633 bool ImGui::VSliderFloat(const char* label, const ImVec2& size, float* v, float v_min, float v_max, const char* display_format, float power, bool render_bg)
6634 {
6636  if (window->SkipItems)
6637  return false;
6638 
6639  ImGuiContext& g = *GImGui;
6640  const ImGuiStyle& style = g.Style;
6641  const ImGuiID id = window->GetID(label);
6642 
6643  const ImVec2 label_size = CalcTextSize(label, NULL, true);
6644  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
6645  const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
6646 
6647  ItemSize(bb, style.FramePadding.y);
6648  if (!ItemAdd(frame_bb, &id))
6649  return false;
6650 
6651  const bool hovered = IsHovered(frame_bb, id);
6652  if (hovered)
6653  SetHoveredID(id);
6654 
6655  if (!display_format)
6656  display_format = "%.3f";
6657  int decimal_precision = ParseFormatPrecision(display_format, 3);
6658 
6659  if (hovered && g.IO.MouseClicked[0])
6660  {
6661  SetActiveID(id, window);
6662  FocusWindow(window);
6663  }
6664 
6665  // Actual slider behavior + render grab
6666  bool value_changed = SliderBehavior(frame_bb, id, v, v_min, v_max, power, decimal_precision, ImGuiSliderFlags_Vertical, render_bg);
6667 
6668  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
6669  // For the vertical slider we allow centered text to overlap the frame padding
6670  char value_buf[64];
6671  char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
6672  RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center);
6673  if (label_size.x > 0.0f)
6674  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
6675 
6676  return value_changed;
6677 }
6678 
6679 bool ImGui::SliderAngle(const char* label, float* v_rad, float v_degrees_min, float v_degrees_max)
6680 {
6681  float v_deg = (*v_rad) * 360.0f / (2*IM_PI);
6682  bool value_changed = SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, "%.0f deg", 1.0f);
6683  *v_rad = v_deg * (2*IM_PI) / 360.0f;
6684  return value_changed;
6685 }
6686 
6687 bool ImGui::SliderInt(const char* label, int* v, int v_min, int v_max, const char* display_format, bool render_bg)
6688 {
6689  if (!display_format)
6690  display_format = "%.0f";
6691  float v_f = (float)*v;
6692  bool value_changed = SliderFloat(label, &v_f, (float)v_min, (float)v_max, display_format, 1.0f, render_bg);
6693  *v = (int)v_f;
6694  return value_changed;
6695 }
6696 
6697 bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* display_format)
6698 {
6699  if (!display_format)
6700  display_format = "%.0f";
6701  float v_f = (float)*v;
6702  bool value_changed = VSliderFloat(label, size, &v_f, (float)v_min, (float)v_max, display_format, 1.0f);
6703  *v = (int)v_f;
6704  return value_changed;
6705 }
6706 
6707 // Add multiple sliders on 1 line for compact edition of multiple components
6708 bool ImGui::SliderFloatN(const char* label, float* v, int components, float v_min, float v_max, const char* display_format, float power)
6709 {
6711  if (window->SkipItems)
6712  return false;
6713 
6714  ImGuiContext& g = *GImGui;
6715  bool value_changed = false;
6716  BeginGroup();
6717  PushID(label);
6718  PushMultiItemsWidths(components);
6719  for (int i = 0; i < components; i++)
6720  {
6721  PushID(i);
6722  value_changed |= SliderFloat("##v", &v[i], v_min, v_max, display_format, power);
6724  PopID();
6725  PopItemWidth();
6726  }
6727  PopID();
6728 
6729  TextUnformatted(label, FindRenderedTextEnd(label));
6730  EndGroup();
6731 
6732  return value_changed;
6733 }
6734 
6735 bool ImGui::SliderFloat2(const char* label, float v[2], float v_min, float v_max, const char* display_format, float power)
6736 {
6737  return SliderFloatN(label, v, 2, v_min, v_max, display_format, power);
6738 }
6739 
6740 bool ImGui::SliderFloat3(const char* label, float v[3], float v_min, float v_max, const char* display_format, float power)
6741 {
6742  return SliderFloatN(label, v, 3, v_min, v_max, display_format, power);
6743 }
6744 
6745 bool ImGui::SliderFloat4(const char* label, float v[4], float v_min, float v_max, const char* display_format, float power)
6746 {
6747  return SliderFloatN(label, v, 4, v_min, v_max, display_format, power);
6748 }
6749 
6750 bool ImGui::SliderIntN(const char* label, int* v, int components, int v_min, int v_max, const char* display_format)
6751 {
6753  if (window->SkipItems)
6754  return false;
6755 
6756  ImGuiContext& g = *GImGui;
6757  bool value_changed = false;
6758  BeginGroup();
6759  PushID(label);
6760  PushMultiItemsWidths(components);
6761  for (int i = 0; i < components; i++)
6762  {
6763  PushID(i);
6764  value_changed |= SliderInt("##v", &v[i], v_min, v_max, display_format);
6766  PopID();
6767  PopItemWidth();
6768  }
6769  PopID();
6770 
6771  TextUnformatted(label, FindRenderedTextEnd(label));
6772  EndGroup();
6773 
6774  return value_changed;
6775 }
6776 
6777 bool ImGui::SliderInt2(const char* label, int v[2], int v_min, int v_max, const char* display_format)
6778 {
6779  return SliderIntN(label, v, 2, v_min, v_max, display_format);
6780 }
6781 
6782 bool ImGui::SliderInt3(const char* label, int v[3], int v_min, int v_max, const char* display_format)
6783 {
6784  return SliderIntN(label, v, 3, v_min, v_max, display_format);
6785 }
6786 
6787 bool ImGui::SliderInt4(const char* label, int v[4], int v_min, int v_max, const char* display_format)
6788 {
6789  return SliderIntN(label, v, 4, v_min, v_max, display_format);
6790 }
6791 
6792 /* Provide GUI slider with values according to interval steps */
6793 bool ImGui::SliderIntWithSteps(const char* label, int * v, int v_min, int v_max, int v_step, const char* display_format)
6794 {
6795  if (!display_format)
6796  display_format = "%d";
6797 
6798  int tmp_val = *v;
6799  bool value_changed = ImGui::SliderInt(label, &tmp_val, v_min, v_max, display_format);
6800 
6801  // Round the actual slider value to the cloasest bound interval
6802  if (v_step > 1)
6803  tmp_val -= (tmp_val - v_min) % v_step;
6804  *v = tmp_val;
6805 
6806  return value_changed;
6807 }
6808 
6809 bool ImGui::DragBehavior(const ImRect& frame_bb, ImGuiID id, float* v, float v_speed, float v_min, float v_max, int decimal_precision, float power)
6810 {
6811  ImGuiContext& g = *GImGui;
6812  const ImGuiStyle& style = g.Style;
6813 
6814  // Draw frame
6816  RenderFrame(frame_bb.Min, frame_bb.Max, frame_col, true, style.FrameRounding);
6817 
6818  bool value_changed = false;
6819 
6820  // Process clicking on the drag
6821  if (g.ActiveId == id)
6822  {
6823  if (g.IO.MouseDown[0])
6824  {
6826  {
6827  // Lock current value on click
6828  g.DragCurrentValue = *v;
6829  g.DragLastMouseDelta = ImVec2(0.f, 0.f);
6830  }
6831 
6832  float v_cur = g.DragCurrentValue;
6833  const ImVec2 mouse_drag_delta = GetMouseDragDelta(0, 1.0f);
6834  if (fabsf(mouse_drag_delta.x - g.DragLastMouseDelta.x) > 0.0f)
6835  {
6836  float speed = v_speed;
6837  if (speed == 0.0f && (v_max - v_min) != 0.0f && (v_max - v_min) < FLT_MAX)
6838  speed = (v_max - v_min) * g.DragSpeedDefaultRatio;
6839  if (g.IO.KeyShift && g.DragSpeedScaleFast >= 0.0f)
6840  speed = speed * g.DragSpeedScaleFast;
6841  if (g.IO.KeyAlt && g.DragSpeedScaleSlow >= 0.0f)
6842  speed = speed * g.DragSpeedScaleSlow;
6843 
6844  float delta = (mouse_drag_delta.x - g.DragLastMouseDelta.x) * speed;
6845  if (fabsf(power - 1.0f) > 0.001f)
6846  {
6847  // Logarithmic curve on both side of 0.0
6848  float v0_abs = v_cur >= 0.0f ? v_cur : -v_cur;
6849  float v0_sign = v_cur >= 0.0f ? 1.0f : -1.0f;
6850  float v1 = powf(v0_abs, 1.0f / power) + (delta * v0_sign);
6851  float v1_abs = v1 >= 0.0f ? v1 : -v1;
6852  float v1_sign = v1 >= 0.0f ? 1.0f : -1.0f; // Crossed sign line
6853  v_cur = powf(v1_abs, power) * v0_sign * v1_sign; // Reapply sign
6854  }
6855  else
6856  {
6857  v_cur += delta;
6858  }
6859  g.DragLastMouseDelta.x = mouse_drag_delta.x;
6860 
6861  // Clamp
6862  if (v_min < v_max)
6863  v_cur = ImClamp(v_cur, v_min, v_max);
6864  g.DragCurrentValue = v_cur;
6865  }
6866 
6867  // Round to user desired precision, then apply
6868  v_cur = RoundScalar(v_cur, decimal_precision);
6869  if (*v != v_cur)
6870  {
6871  *v = v_cur;
6872  value_changed = true;
6873  }
6874  }
6875  else
6876  {
6877  SetActiveID(0);
6878  }
6879  }
6880 
6881  return value_changed;
6882 }
6883 
6884 bool ImGui::DragFloat(const char* label, float* v, float v_speed, float v_min, float v_max, const char* display_format, float power)
6885 {
6887  if (window->SkipItems)
6888  return false;
6889 
6890  ImGuiContext& g = *GImGui;
6891  const ImGuiStyle& style = g.Style;
6892  const ImGuiID id = window->GetID(label);
6893  const float w = CalcItemWidth();
6894 
6895  const ImVec2 label_size = CalcTextSize(label, NULL, true);
6896  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
6897  const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
6898  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
6899 
6900  // NB- we don't call ItemSize() yet because we may turn into a text edit box below
6901  if (!ItemAdd(total_bb, &id))
6902  {
6903  ItemSize(total_bb, style.FramePadding.y);
6904  return false;
6905  }
6906 
6907  const bool hovered = IsHovered(frame_bb, id);
6908  if (hovered)
6909  SetHoveredID(id);
6910 
6911  if (!display_format)
6912  display_format = "%.3f";
6913  int decimal_precision = ParseFormatPrecision(display_format, 3);
6914 
6915  // Tabbing or CTRL-clicking on Drag turns it into an input box
6916  bool start_text_input = false;
6917  const bool tab_focus_requested = FocusableItemRegister(window, g.ActiveId == id);
6918  if (tab_focus_requested || (hovered && (g.IO.MouseClicked[0] | g.IO.MouseDoubleClicked[0])))
6919  {
6920  SetActiveID(id, window);
6921  FocusWindow(window);
6922 
6923  if (tab_focus_requested || g.IO.KeyCtrl || g.IO.MouseDoubleClicked[0])
6924  {
6925  start_text_input = true;
6926  g.ScalarAsInputTextId = 0;
6927  }
6928  }
6929  if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id))
6930  return InputScalarAsWidgetReplacement(frame_bb, label, ImGuiDataType_Float, v, id, decimal_precision);
6931 
6932  // Actual drag behavior
6933  ItemSize(total_bb, style.FramePadding.y);
6934  const bool value_changed = DragBehavior(frame_bb, id, v, v_speed, v_min, v_max, decimal_precision, power);
6935 
6936  // Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
6937  char value_buf[64];
6938  const char* value_buf_end = value_buf + ImFormatString(value_buf, IM_ARRAYSIZE(value_buf), display_format, *v);
6939  RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImGuiAlign_Center|ImGuiAlign_VCenter);
6940 
6941  if (label_size.x > 0.0f)
6942  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
6943 
6944  return value_changed;
6945 }
6946 
6947 bool ImGui::DragFloatN(const char* label, float* v, int components, float v_speed, float v_min, float v_max, const char* display_format, float power)
6948 {
6950  if (window->SkipItems)
6951  return false;
6952 
6953  ImGuiContext& g = *GImGui;
6954  bool value_changed = false;
6955  BeginGroup();
6956  PushID(label);
6957  PushMultiItemsWidths(components);
6958  for (int i = 0; i < components; i++)
6959  {
6960  PushID(i);
6961  value_changed |= DragFloat("##v", &v[i], v_speed, v_min, v_max, display_format, power);
6963  PopID();
6964  PopItemWidth();
6965  }
6966  PopID();
6967 
6968  TextUnformatted(label, FindRenderedTextEnd(label));
6969  EndGroup();
6970 
6971  return value_changed;
6972 }
6973 
6974 bool ImGui::DragFloat2(const char* label, float v[2], float v_speed, float v_min, float v_max, const char* display_format, float power)
6975 {
6976  return DragFloatN(label, v, 2, v_speed, v_min, v_max, display_format, power);
6977 }
6978 
6979 bool ImGui::DragFloat3(const char* label, float v[3], float v_speed, float v_min, float v_max, const char* display_format, float power)
6980 {
6981  return DragFloatN(label, v, 3, v_speed, v_min, v_max, display_format, power);
6982 }
6983 
6984 bool ImGui::DragFloat4(const char* label, float v[4], float v_speed, float v_min, float v_max, const char* display_format, float power)
6985 {
6986  return DragFloatN(label, v, 4, v_speed, v_min, v_max, display_format, power);
6987 }
6988 
6989 bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_current_max, float v_speed, float v_min, float v_max, const char* display_format, const char* display_format_max, float power)
6990 {
6992  if (window->SkipItems)
6993  return false;
6994 
6995  ImGuiContext& g = *GImGui;
6996  PushID(label);
6997  BeginGroup();
6999 
7000  bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format, power);
7001  PopItemWidth();
7003  value_changed |= DragFloat("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? FLT_MAX : v_max, display_format_max ? display_format_max : display_format, power);
7004  PopItemWidth();
7006 
7007  TextUnformatted(label, FindRenderedTextEnd(label));
7008  EndGroup();
7009  PopID();
7010 
7011  return value_changed;
7012 }
7013 
7014 // NB: v_speed is float to allow adjusting the drag speed with more precision
7015 bool ImGui::DragInt(const char* label, int* v, float v_speed, int v_min, int v_max, const char* display_format)
7016 {
7017  if (!display_format)
7018  display_format = "%.0f";
7019  float v_f = (float)*v;
7020  bool value_changed = DragFloat(label, &v_f, v_speed, (float)v_min, (float)v_max, display_format);
7021  *v = (int)v_f;
7022  return value_changed;
7023 }
7024 
7025 bool ImGui::DragIntN(const char* label, int* v, int components, float v_speed, int v_min, int v_max, const char* display_format)
7026 {
7028  if (window->SkipItems)
7029  return false;
7030 
7031  ImGuiContext& g = *GImGui;
7032  bool value_changed = false;
7033  BeginGroup();
7034  PushID(label);
7035  PushMultiItemsWidths(components);
7036  for (int i = 0; i < components; i++)
7037  {
7038  PushID(i);
7039  value_changed |= DragInt("##v", &v[i], v_speed, v_min, v_max, display_format);
7041  PopID();
7042  PopItemWidth();
7043  }
7044  PopID();
7045 
7046  TextUnformatted(label, FindRenderedTextEnd(label));
7047  EndGroup();
7048 
7049  return value_changed;
7050 }
7051 
7052 bool ImGui::DragInt2(const char* label, int v[2], float v_speed, int v_min, int v_max, const char* display_format)
7053 {
7054  return DragIntN(label, v, 2, v_speed, v_min, v_max, display_format);
7055 }
7056 
7057 bool ImGui::DragInt3(const char* label, int v[3], float v_speed, int v_min, int v_max, const char* display_format)
7058 {
7059  return DragIntN(label, v, 3, v_speed, v_min, v_max, display_format);
7060 }
7061 
7062 bool ImGui::DragInt4(const char* label, int v[4], float v_speed, int v_min, int v_max, const char* display_format)
7063 {
7064  return DragIntN(label, v, 4, v_speed, v_min, v_max, display_format);
7065 }
7066 
7067 bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_max, float v_speed, int v_min, int v_max, const char* display_format, const char* display_format_max)
7068 {
7070  if (window->SkipItems)
7071  return false;
7072 
7073  ImGuiContext& g = *GImGui;
7074  PushID(label);
7075  BeginGroup();
7077 
7078  bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), display_format);
7079  PopItemWidth();
7081  value_changed |= DragInt("##max", v_current_max, v_speed, (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min), (v_min >= v_max) ? INT_MAX : v_max, display_format_max ? display_format_max : display_format);
7082  PopItemWidth();
7084 
7085  TextUnformatted(label, FindRenderedTextEnd(label));
7086  EndGroup();
7087  PopID();
7088 
7089  return value_changed;
7090 }
7091 
7092 void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
7093 {
7095  if (window->SkipItems)
7096  return;
7097 
7098  ImGuiContext& g = *GImGui;
7099  const ImGuiStyle& style = g.Style;
7100 
7101  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7102  if (graph_size.x == 0.0f)
7103  graph_size.x = CalcItemWidth();
7104  if (graph_size.y == 0.0f)
7105  graph_size.y = label_size.y + (style.FramePadding.y * 2);
7106 
7107  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(graph_size.x, graph_size.y));
7108  const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
7109  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));
7110  ItemSize(total_bb, style.FramePadding.y);
7111  if (!ItemAdd(total_bb, NULL))
7112  return;
7113 
7114  // Determine scale from values if not specified
7115  if (scale_min == FLT_MAX || scale_max == FLT_MAX)
7116  {
7117  float v_min = FLT_MAX;
7118  float v_max = -FLT_MAX;
7119  for (int i = 0; i < values_count; i++)
7120  {
7121  const float v = values_getter(data, i);
7122  v_min = ImMin(v_min, v);
7123  v_max = ImMax(v_max, v);
7124  }
7125  if (scale_min == FLT_MAX)
7126  scale_min = v_min;
7127  if (scale_max == FLT_MAX)
7128  scale_max = v_max;
7129  }
7130 
7131  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
7132 
7133  int res_w = ImMin((int)graph_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
7134  int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
7135 
7136  // Tooltip on hover
7137  int v_hovered = -1;
7138  if (IsHovered(inner_bb, 0))
7139  {
7140  const float t = ImClamp((g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
7141  const int v_idx = (int)(t * item_count);
7142  IM_ASSERT(v_idx >= 0 && v_idx < values_count);
7143 
7144  const float v0 = values_getter(data, (v_idx + values_offset) % values_count);
7145  const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count);
7146  if (plot_type == ImGuiPlotType_Lines)
7147  SetTooltip("%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx+1, v1);
7148  else if (plot_type == ImGuiPlotType_Histogram)
7149  SetTooltip("%d: %8.4g", v_idx, v0);
7150  v_hovered = v_idx;
7151  }
7152 
7153  const float t_step = 1.0f / (float)res_w;
7154 
7155  float v0 = values_getter(data, (0 + values_offset) % values_count);
7156  float t0 = 0.0f;
7157  ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) / (scale_max - scale_min)) ); // Point in the normalized space of our target rectangle
7158 
7159  const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);
7161 
7162  for (int n = 0; n < res_w; n++)
7163  {
7164  const float t1 = t0 + t_step;
7165  const int v1_idx = (int)(t0 * item_count + 0.5f);
7166  IM_ASSERT(v1_idx >= 0 && v1_idx < values_count);
7167  const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count);
7168  const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) / (scale_max - scale_min)) );
7169 
7170  // NB: Draw calls are merged together by the DrawList system. Still, we should render our batch are lower level to save a bit of CPU.
7171  ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0);
7172  ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, 1.0f));
7173  if (plot_type == ImGuiPlotType_Lines)
7174  {
7175  window->DrawList->AddLine(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
7176  }
7177  else if (plot_type == ImGuiPlotType_Histogram)
7178  {
7179  if (pos1.x >= pos0.x + 2.0f)
7180  pos1.x -= 1.0f;
7181  window->DrawList->AddRectFilled(pos0, pos1, v_hovered == v1_idx ? col_hovered : col_base);
7182  }
7183 
7184  t0 = t1;
7185  tp0 = tp1;
7186  }
7187 
7188  // Text overlay
7189  if (overlay_text)
7190  RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImGuiAlign_Center);
7191 
7192  if (label_size.x > 0.0f)
7193  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
7194 }
7195 
7197 {
7198  const float* Values;
7199  int Stride;
7200 
7201  ImGuiPlotArrayGetterData(const float* values, int stride) { Values = values; Stride = stride; }
7202 };
7203 
7204 static float Plot_ArrayGetter(void* data, int idx)
7205 {
7207  const float v = *(float*)(void*)((unsigned char*)plot_data->Values + (size_t)idx * plot_data->Stride);
7208  return v;
7209 }
7210 
7211 void ImGui::PlotLines(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
7212 {
7213  ImGuiPlotArrayGetterData data(values, stride);
7214  PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7215 }
7216 
7217 void ImGui::PlotLines(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
7218 {
7219  PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7220 }
7221 
7222 void ImGui::PlotHistogram(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride)
7223 {
7224  ImGuiPlotArrayGetterData data(values, stride);
7225  PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7226 }
7227 
7228 void ImGui::PlotHistogram(const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
7229 {
7230  PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7231 }
7232 
7233 // size_arg (for each axis) < 0.0f: align to end, 0.0f: auto, > 0.0f: specified size
7234 void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* overlay)
7235 {
7237  if (window->SkipItems)
7238  return;
7239 
7240  ImGuiContext& g = *GImGui;
7241  const ImGuiStyle& style = g.Style;
7242 
7243  ImVec2 pos = window->DC.CursorPos;
7244  ImRect bb(pos, pos + CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f));
7245  ItemSize(bb, style.FramePadding.y);
7246  if (!ItemAdd(bb, NULL))
7247  return;
7248 
7249  // Render
7250  fraction = ImSaturate(fraction);
7252  bb.Reduce(ImVec2(window->BorderSize, window->BorderSize));
7253  const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);
7254  RenderFrame(bb.Min, fill_br, GetColorU32(ImGuiCol_PlotHistogram), false, style.FrameRounding);
7255 
7256  // Default displaying the fraction as percentage string, but user can override it
7257  char overlay_buf[32];
7258  if (!overlay)
7259  {
7260  ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.0f%%", fraction*100+0.01f);
7261  overlay = overlay_buf;
7262  }
7263 
7264  ImVec2 overlay_size = CalcTextSize(overlay, NULL);
7265  if (overlay_size.x > 0.0f)
7266  RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImGuiAlign_Left|ImGuiAlign_VCenter, &bb.Min, &bb.Max);
7267 }
7268 
7269 bool ImGui::Checkbox(const char* label, bool* v)
7270 {
7272  if (window->SkipItems)
7273  return false;
7274 
7275  ImGuiContext& g = *GImGui;
7276  const ImGuiStyle& style = g.Style;
7277  const ImGuiID id = window->GetID(label);
7278  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7279 
7280  const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2));
7281  ItemSize(check_bb, style.FramePadding.y);
7282 
7283  ImRect total_bb = check_bb;
7284  if (label_size.x > 0)
7285  SameLine(0, style.ItemInnerSpacing.x);
7286  const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size);
7287  if (label_size.x > 0)
7288  {
7289  ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
7290  total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max));
7291  }
7292 
7293  if (!ItemAdd(total_bb, &id))
7294  return false;
7295 
7296  bool hovered, held;
7297  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
7298  if (pressed)
7299  *v = !(*v);
7300 
7301  RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
7302  if (*v)
7303  {
7304  const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
7305  const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
7306  window->DrawList->AddRectFilled(check_bb.Min+ImVec2(pad,pad), check_bb.Max-ImVec2(pad,pad), GetColorU32(ImGuiCol_CheckMark), style.FrameRounding);
7307  }
7308 
7309  if (g.LogEnabled)
7310  LogRenderedText(text_bb.GetTL(), *v ? "[x]" : "[ ]");
7311  if (label_size.x > 0.0f)
7312  RenderText(text_bb.GetTL(), label);
7313 
7314  return pressed;
7315 }
7316 
7317 bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value)
7318 {
7319  bool v = ((*flags & flags_value) == flags_value);
7320  bool pressed = Checkbox(label, &v);
7321  if (pressed)
7322  {
7323  if (v)
7324  *flags |= flags_value;
7325  else
7326  *flags &= ~flags_value;
7327  }
7328 
7329  return pressed;
7330 }
7331 
7332 bool ImGui::RadioButton(const char* label, bool active)
7333 {
7335  if (window->SkipItems)
7336  return false;
7337 
7338  ImGuiContext& g = *GImGui;
7339  const ImGuiStyle& style = g.Style;
7340  const ImGuiID id = window->GetID(label);
7341  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7342 
7343  const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2-1, label_size.y + style.FramePadding.y*2-1));
7344  ItemSize(check_bb, style.FramePadding.y);
7345 
7346  ImRect total_bb = check_bb;
7347  if (label_size.x > 0)
7348  SameLine(0, style.ItemInnerSpacing.x);
7349  const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size);
7350  if (label_size.x > 0)
7351  {
7352  ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y);
7353  total_bb.Add(text_bb);
7354  }
7355 
7356  if (!ItemAdd(total_bb, &id))
7357  return false;
7358 
7359  ImVec2 center = check_bb.GetCenter();
7360  center.x = (float)(int)center.x + 0.5f;
7361  center.y = (float)(int)center.y + 0.5f;
7362  const float radius = check_bb.GetHeight() * 0.5f;
7363 
7364  bool hovered, held;
7365  bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
7366 
7367  window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16);
7368  if (active)
7369  {
7370  const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight());
7371  const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f));
7372  window->DrawList->AddCircleFilled(center, radius-pad, GetColorU32(ImGuiCol_CheckMark), 16);
7373  }
7374 
7375  if (window->Flags & ImGuiWindowFlags_ShowBorders)
7376  {
7377  window->DrawList->AddCircle(center+ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16);
7378  window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16);
7379  }
7380 
7381  if (g.LogEnabled)
7382  LogRenderedText(text_bb.GetTL(), active ? "(x)" : "( )");
7383  if (label_size.x > 0.0f)
7384  RenderText(text_bb.GetTL(), label);
7385 
7386  return pressed;
7387 }
7388 
7389 bool ImGui::RadioButton(const char* label, int* v, int v_button)
7390 {
7391  const bool pressed = RadioButton(label, *v == v_button);
7392  if (pressed)
7393  {
7394  *v = v_button;
7395  }
7396  return pressed;
7397 }
7398 
7399 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end)
7400 {
7401  int line_count = 0;
7402  const char* s = text_begin;
7403  while (char c = *s++) // We are only matching for \n so we can ignore UTF-8 decoding
7404  if (c == '\n')
7405  line_count++;
7406  s--;
7407  if (s[0] != '\n' && s[0] != '\r')
7408  line_count++;
7409  *out_text_end = s;
7410  return line_count;
7411 }
7412 
7413 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining, ImVec2* out_offset, bool stop_on_new_line)
7414 {
7415  ImFont* font = GImGui->Font;
7416  const float line_height = GImGui->FontSize;
7417  const float scale = line_height / font->FontSize;
7418 
7419  ImVec2 text_size = ImVec2(0,0);
7420  float line_width = 0.0f;
7421 
7422  const ImWchar* s = text_begin;
7423  while (s < text_end)
7424  {
7425  unsigned int c = (unsigned int)(*s++);
7426  if (c == '\n')
7427  {
7428  text_size.x = ImMax(text_size.x, line_width);
7429  text_size.y += line_height;
7430  line_width = 0.0f;
7431  if (stop_on_new_line)
7432  break;
7433  continue;
7434  }
7435  if (c == '\r')
7436  continue;
7437 
7438  const float char_width = font->GetCharAdvance((unsigned short)c) * scale;
7439  line_width += char_width;
7440  }
7441 
7442  if (text_size.x < line_width)
7443  text_size.x = line_width;
7444 
7445  if (out_offset)
7446  *out_offset = ImVec2(line_width, text_size.y + line_height); // offset allow for the possibility of sitting after a trailing \n
7447 
7448  if (line_width > 0 || text_size.y == 0.0f) // whereas size.y will ignore the trailing \n
7449  text_size.y += line_height;
7450 
7451  if (remaining)
7452  *remaining = s;
7453 
7454  return text_size;
7455 }
7456 
7457 // Wrapper for stb_textedit.h to edit text (our wrapper is for: statically sized buffer, single-line, wchar characters. InputText converts between UTF-8 and wchar)
7458 namespace ImGuiStb
7459 {
7460 
7461 static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING* obj) { return obj->CurLenW; }
7462 static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING* obj, int idx) { return obj->Text[idx]; }
7463 static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING* obj, int line_start_idx, int char_idx) { ImWchar c = obj->Text[line_start_idx+char_idx]; if (c == '\n') return STB_TEXTEDIT_GETWIDTH_NEWLINE; return GImGui->Font->GetCharAdvance(c) * (GImGui->FontSize / GImGui->Font->FontSize); }
7464 static int STB_TEXTEDIT_KEYTOTEXT(int key) { return key >= 0x10000 ? 0 : key; }
7467 {
7468  const ImWchar* text = obj->Text.Data;
7469  const ImWchar* text_remaining = NULL;
7470  const ImVec2 size = InputTextCalcTextSizeW(text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL, true);
7471  r->x0 = 0.0f;
7472  r->x1 = size.x;
7473  r->baseline_y_delta = size.y;
7474  r->ymin = 0.0f;
7475  r->ymax = size.y;
7476  r->num_chars = (int)(text_remaining - (text + line_start_idx));
7477 }
7478 
7479 static bool is_separator(unsigned int c) { return ImCharIsSpace(c) || c==',' || c==';' || c=='(' || c==')' || c=='{' || c=='}' || c=='[' || c==']' || c=='|'; }
7480 static int is_word_boundary_from_right(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (is_separator( obj->Text[idx-1] ) && !is_separator( obj->Text[idx] ) ) : 1; }
7481 static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
7482 #ifdef __APPLE__ // FIXME: Move setting to IO structure
7483 static int is_word_boundary_from_left(STB_TEXTEDIT_STRING* obj, int idx) { return idx > 0 ? (!is_separator( obj->Text[idx-1] ) && is_separator( obj->Text[idx] ) ) : 1; }
7484 static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
7485 #else
7486 static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING* obj, int idx) { int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
7487 #endif
7488 #define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h
7489 #define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
7490 
7492 {
7493  ImWchar* dst = obj->Text.Data + pos;
7494 
7495  // We maintain our buffer length in both UTF-8 and wchar formats
7496  obj->CurLenA -= ImTextCountUtf8BytesFromStr(dst, dst + n);
7497  obj->CurLenW -= n;
7498 
7499  // Offset remaining text
7500  const ImWchar* src = obj->Text.Data + pos + n;
7501  while (ImWchar c = *src++)
7502  *dst++ = c;
7503  *dst = '\0';
7504 }
7505 
7506 static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const ImWchar* new_text, int new_text_len)
7507 {
7508  const int text_len = obj->CurLenW;
7509  if (new_text_len + text_len + 1 > obj->Text.Size)
7510  return false;
7511 
7512  const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len);
7513  if (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufSizeA)
7514  return false;
7515 
7516  ImWchar* text = obj->Text.Data;
7517  if (pos != text_len)
7518  memmove(text + pos + new_text_len, text + pos, (size_t)(text_len - pos) * sizeof(ImWchar));
7519  memcpy(text + pos, new_text, (size_t)new_text_len * sizeof(ImWchar));
7520 
7521  obj->CurLenW += new_text_len;
7522  obj->CurLenA += new_text_len_utf8;
7523  obj->Text[obj->CurLenW] = '\0';
7524 
7525  return true;
7526 }
7527 
7528 // We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols)
7529 #define STB_TEXTEDIT_K_LEFT 0x10000 // keyboard input to move cursor left
7530 #define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right
7531 #define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up
7532 #define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down
7533 #define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line
7534 #define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line
7535 #define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text
7536 #define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text
7537 #define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor
7538 #define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor
7539 #define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo
7540 #define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo
7541 #define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word
7542 #define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word
7543 #define STB_TEXTEDIT_K_SHIFT 0x20000
7544 
7545 #define STB_TEXTEDIT_IMPLEMENTATION
7546 #include "stb_textedit.h"
7547 
7548 }
7549 
7551 {
7552  stb_textedit_key(this, &StbState, key);
7553  CursorFollow = true;
7554  CursorAnimReset();
7555 }
7556 
7557 // Public API to manipulate UTF-8 text
7558 // We expose UTF-8 to the user (unlike the STB_TEXTEDIT_* functions which are manipulating wchar)
7559 // FIXME: The existence of this rarely exercised code path is a bit of a nuisance.
7561 {
7562  IM_ASSERT(pos + bytes_count <= BufTextLen);
7563  char* dst = Buf + pos;
7564  const char* src = Buf + pos + bytes_count;
7565  while (char c = *src++)
7566  *dst++ = c;
7567  *dst = '\0';
7568 
7569  if (CursorPos + bytes_count >= pos)
7570  CursorPos -= bytes_count;
7571  else if (CursorPos >= pos)
7572  CursorPos = pos;
7573  SelectionStart = SelectionEnd = CursorPos;
7574  BufDirty = true;
7575  BufTextLen -= bytes_count;
7576 }
7577 
7578 void ImGuiTextEditCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
7579 {
7580  const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
7581  if (new_text_len + BufTextLen + 1 >= BufSize)
7582  return;
7583 
7584  if (BufTextLen != pos)
7585  memmove(Buf + pos + new_text_len, Buf + pos, (size_t)(BufTextLen - pos));
7586  memcpy(Buf + pos, new_text, (size_t)new_text_len * sizeof(char));
7587  Buf[BufTextLen + new_text_len] = '\0';
7588 
7589  if (CursorPos >= pos)
7590  CursorPos += new_text_len;
7591  SelectionStart = SelectionEnd = CursorPos;
7592  BufDirty = true;
7593  BufTextLen += new_text_len;
7594 }
7595 
7596 // Return false to discard a character.
7598 {
7599  unsigned int c = *p_char;
7600 
7601  if (c < 128 && c != ' ' && !isprint((int)(c & 0xFF)))
7602  {
7603  bool pass = false;
7604  pass |= (c == '\n' && (flags & ImGuiInputTextFlags_Multiline));
7605  pass |= (c == '\t' && (flags & ImGuiInputTextFlags_AllowTabInput));
7606  if (!pass)
7607  return false;
7608  }
7609 
7610  if (c >= 0xE000 && c <= 0xF8FF) // Filter private Unicode range. I don't imagine anybody would want to input them. GLFW on OSX seems to send private characters for special keys like arrow keys.
7611  return false;
7612 
7614  {
7616  if (!(c >= '0' && c <= '9') && (c != '.') && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
7617  return false;
7618 
7620  if (!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))
7621  return false;
7622 
7624  if (c >= 'a' && c <= 'z')
7625  *p_char = (c += (unsigned int)('A'-'a'));
7626 
7628  if (ImCharIsSpace(c))
7629  return false;
7630  }
7631 
7633  {
7634  ImGuiTextEditCallbackData callback_data;
7635  memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
7637  callback_data.EventChar = (ImWchar)c;
7638  callback_data.Flags = flags;
7639  callback_data.UserData = user_data;
7640  if (callback(&callback_data) != 0)
7641  return false;
7642  *p_char = callback_data.EventChar;
7643  if (!callback_data.EventChar)
7644  return false;
7645  }
7646 
7647  return true;
7648 }
7649 
7650 // Edit a string of text
7651 // NB: when active, hold on a privately held copy of the text (and apply back to 'buf'). So changing 'buf' while active has no effect.
7652 // FIXME: Rather messy function partly because we are doing UTF8 > u16 > UTF8 conversions on the go to more easily handle stb_textedit calls. Ideally we should stay in UTF-8 all the time. See https://github.com/nothings/stb/issues/188
7653 bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
7654 {
7656  if (window->SkipItems)
7657  return false;
7658 
7659  IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline))); // Can't use both together (they both use up/down keys)
7660  IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput))); // Can't use both together (they both use tab key)
7661 
7662  ImGuiContext& g = *GImGui;
7663  const ImGuiIO& io = g.IO;
7664  const ImGuiStyle& style = g.Style;
7665 
7666  const ImGuiID id = window->GetID(label);
7667  const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
7668  const bool is_editable = (flags & ImGuiInputTextFlags_ReadOnly) == 0;
7669  const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
7670 
7671  const ImVec2 label_size = CalcTextSize(label, NULL, true);
7672  ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
7673  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
7674  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f));
7675 
7676  ImGuiWindow* draw_window = window;
7677  if (is_multiline)
7678  {
7679  BeginGroup();
7680  if (!BeginChildFrame(id, frame_bb.GetSize()))
7681  {
7682  EndChildFrame();
7683  EndGroup();
7684  return false;
7685  }
7686  draw_window = GetCurrentWindow();
7687  size.x -= draw_window->ScrollbarSizes.x;
7688  }
7689  else
7690  {
7691  ItemSize(total_bb, style.FramePadding.y);
7692  if (!ItemAdd(total_bb, &id))
7693  return false;
7694  }
7695 
7696  // Password pushes a temporary font with only a fallback glyph
7697  if (is_password)
7698  {
7699  const ImFont::Glyph* glyph = g.Font->FindGlyph('*');
7700  ImFont* password_font = &g.InputTextPasswordFont;
7701  password_font->FontSize = g.Font->FontSize;
7702  password_font->Scale = g.Font->Scale;
7703  password_font->DisplayOffset = g.Font->DisplayOffset;
7704  password_font->Ascent = g.Font->Ascent;
7705  password_font->Descent = g.Font->Descent;
7706  password_font->ContainerAtlas = g.Font->ContainerAtlas;
7707  password_font->FallbackGlyph = glyph;
7708  password_font->FallbackXAdvance = glyph->XAdvance;
7709  IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexXAdvance.empty() && password_font->IndexLookup.empty());
7710  PushFont(password_font);
7711  }
7712 
7713  // NB: we are only allowed to access 'edit_state' if we are the active widget.
7714  ImGuiTextEditState& edit_state = g.InputTextState;
7715 
7716  const bool is_ctrl_down = io.KeyCtrl;
7717  const bool is_shift_down = io.KeyShift;
7718  const bool is_alt_down = io.KeyAlt;
7719  const bool is_super_down = io.KeySuper;
7720  const bool focus_requested = FocusableItemRegister(window, g.ActiveId == id, (flags & (ImGuiInputTextFlags_CallbackCompletion|ImGuiInputTextFlags_AllowTabInput)) == 0); // Using completion callback disable keyboard tabbing
7721  const bool focus_requested_by_code = focus_requested && (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent);
7722  const bool focus_requested_by_tab = focus_requested && !focus_requested_by_code;
7723 
7724  const bool hovered = IsHovered(frame_bb, id);
7725  if (hovered)
7726  {
7727  SetHoveredID(id);
7729  }
7730  const bool user_clicked = hovered && io.MouseClicked[0];
7731  const bool user_scrolled = is_multiline && g.ActiveId == 0 && edit_state.Id == id && g.ActiveIdPreviousFrame == draw_window->GetID("#SCROLLY");
7732 
7733  bool select_all = (g.ActiveId != id) && (flags & ImGuiInputTextFlags_AutoSelectAll) != 0;
7734  if (focus_requested || user_clicked || user_scrolled)
7735  {
7736  if (g.ActiveId != id)
7737  {
7738  // Start edition
7739  // Take a copy of the initial buffer value (both in original UTF-8 format and converted to wchar)
7740  // From the moment we focused we are ignoring the content of 'buf' (unless we are in read-only mode)
7741  const int prev_len_w = edit_state.CurLenW;
7742  edit_state.Text.resize(buf_size+1); // wchar count <= utf-8 count. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
7743  edit_state.InitialText.resize(buf_size+1); // utf-8. we use +1 to make sure that .Data isn't NULL so it doesn't crash.
7744  ImFormatString(edit_state.InitialText.Data, edit_state.InitialText.Size, "%s", buf);
7745  const char* buf_end = NULL;
7746  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
7747  edit_state.CurLenA = (int)(buf_end - buf); // We can't get the result from ImFormatString() above because it is not UTF-8 aware. Here we'll cut off malformed UTF-8.
7748  edit_state.CursorAnimReset();
7749 
7750  // Preserve cursor position and undo/redo stack if we come back to same widget
7751  // FIXME: We should probably compare the whole buffer to be on the safety side. Comparing buf (utf8) and edit_state.Text (wchar).
7752  const bool recycle_state = (edit_state.Id == id) && (prev_len_w == edit_state.CurLenW);
7753  if (recycle_state)
7754  {
7755  // Recycle existing cursor/selection/undo stack but clamp position
7756  // Note a single mouse click will override the cursor/position immediately by calling stb_textedit_click handler.
7757  edit_state.CursorClamp();
7758  }
7759  else
7760  {
7761  edit_state.Id = id;
7762  edit_state.ScrollX = 0.0f;
7763  stb_textedit_initialize_state(&edit_state.StbState, !is_multiline);
7764  if (!is_multiline && focus_requested_by_code)
7765  select_all = true;
7766  }
7768  edit_state.StbState.insert_mode = true;
7769  if (!is_multiline && (focus_requested_by_tab || (user_clicked && is_ctrl_down)))
7770  select_all = true;
7771  }
7772  SetActiveID(id, window);
7773  FocusWindow(window);
7774  }
7775  else if (io.MouseClicked[0])
7776  {
7777  // Release focus when we click outside
7778  if (g.ActiveId == id)
7779  SetActiveID(0);
7780  }
7781 
7782  bool value_changed = false;
7783  bool enter_pressed = false;
7784 
7785  if (g.ActiveId == id)
7786  {
7787  if (!is_editable && !g.ActiveIdIsJustActivated)
7788  {
7789  // When read-only we always use the live data passed to the function
7790  edit_state.Text.resize(buf_size+1);
7791  const char* buf_end = NULL;
7792  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, buf, NULL, &buf_end);
7793  edit_state.CurLenA = (int)(buf_end - buf);
7794  edit_state.CursorClamp();
7795  }
7796 
7797  edit_state.BufSizeA = buf_size;
7798 
7799  // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
7800  // Down the line we should have a cleaner library-wide concept of Selected vs Active.
7801  g.ActiveIdAllowOverlap = !io.MouseDown[0];
7802 
7803  // Edit in progress
7804  const float mouse_x = (g.IO.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + edit_state.ScrollX;
7805  const float mouse_y = (is_multiline ? (g.IO.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize*0.5f));
7806 
7807  if (select_all || (hovered && !io.DoubleClickSelectsWord && io.MouseDoubleClicked[0]))
7808  {
7809  edit_state.SelectAll();
7810  edit_state.SelectedAllMouseLock = true;
7811  }
7812  else if (hovered && io.DoubleClickSelectsWord && io.MouseDoubleClicked[0])
7813  {
7814  // Select a word only, OS X style (by simulating keystrokes)
7817  }
7818  else if (io.MouseClicked[0] && !edit_state.SelectedAllMouseLock)
7819  {
7820  stb_textedit_click(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
7821  edit_state.CursorAnimReset();
7822  }
7823  else if (io.MouseDown[0] && !edit_state.SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
7824  {
7825  stb_textedit_drag(&edit_state, &edit_state.StbState, mouse_x, mouse_y);
7826  edit_state.CursorAnimReset();
7827  edit_state.CursorFollow = true;
7828  }
7829  if (edit_state.SelectedAllMouseLock && !io.MouseDown[0])
7830  edit_state.SelectedAllMouseLock = false;
7831 
7832  if (g.IO.InputCharacters[0])
7833  {
7834  // Process text input (before we check for Return because using some IME will effectively send a Return?)
7835  // We ignore CTRL inputs, but need to allow CTRL+ALT as some keyboards (e.g. German) use AltGR - which is Alt+Ctrl - to input certain characters.
7836  if (!(is_ctrl_down && !is_alt_down) && is_editable)
7837  {
7838  for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++)
7839  if (unsigned int c = (unsigned int)g.IO.InputCharacters[n])
7840  {
7841  // Insert character if they pass filtering
7842  if (!InputTextFilterCharacter(&c, flags, callback, user_data))
7843  continue;
7844  edit_state.OnKeyPressed((int)c);
7845  }
7846  }
7847 
7848  // Consume characters
7849  memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters));
7850  }
7851 
7852  // Handle various key-presses
7853  bool cancel_edit = false;
7854  const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0);
7855  const bool is_shortcutkey_only = (io.ShortcutsUseSuperKey ? (is_super_down && !is_alt_down && !is_shift_down && !is_ctrl_down) : (is_ctrl_down && !is_alt_down && !is_shift_down && !is_super_down));
7856  const bool is_wordmove_key_down = (io.WordMovementUsesAltKey ? io.KeyAlt : io.KeyCtrl);
7857 
7858  if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); }
7859  else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); }
7860  else if (is_multiline && IsKeyPressedMap(ImGuiKey_UpArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y - g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_UP | k_mask); }
7861  else if (is_multiline && IsKeyPressedMap(ImGuiKey_DownArrow)) { if (is_ctrl_down) SetWindowScrollY(draw_window, draw_window->Scroll.y + g.FontSize); else edit_state.OnKeyPressed(STB_TEXTEDIT_K_DOWN| k_mask); }
7862  else if (IsKeyPressedMap(ImGuiKey_Home)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
7863  else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
7864  else if (IsKeyPressedMap(ImGuiKey_Delete) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
7865  else if (IsKeyPressedMap(ImGuiKey_Backspace) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); }
7866  else if (IsKeyPressedMap(ImGuiKey_Enter))
7867  {
7868  bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
7869  if (!is_multiline || (ctrl_enter_for_new_line && !is_ctrl_down) || (!ctrl_enter_for_new_line && is_ctrl_down))
7870  {
7871  SetActiveID(0);
7872  enter_pressed = true;
7873  }
7874  else if (is_editable)
7875  {
7876  unsigned int c = '\n'; // Insert new line
7877  if (InputTextFilterCharacter(&c, flags, callback, user_data))
7878  edit_state.OnKeyPressed((int)c);
7879  }
7880  }
7881  else if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressedMap(ImGuiKey_Tab) && !is_ctrl_down && !is_shift_down && !is_alt_down && is_editable)
7882  {
7883  unsigned int c = '\t'; // Insert TAB
7884  if (InputTextFilterCharacter(&c, flags, callback, user_data))
7885  edit_state.OnKeyPressed((int)c);
7886  }
7887  else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveID(0); cancel_edit = true; }
7888  else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); }
7889  else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); }
7890  else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; }
7891  else if (is_shortcutkey_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection()))
7892  {
7893  // Cut, Copy
7894  const bool cut = IsKeyPressedMap(ImGuiKey_X);
7895  if (cut && !edit_state.HasSelection())
7896  edit_state.SelectAll();
7897 
7898  if (g.IO.SetClipboardTextFn)
7899  {
7900  const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0;
7901  const int ie = edit_state.HasSelection() ? ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end) : edit_state.CurLenW;
7902  edit_state.TempTextBuffer.resize((ie-ib) * 4 + 1);
7903  ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data+ib, edit_state.Text.Data+ie);
7904  g.IO.SetClipboardTextFn(edit_state.TempTextBuffer.Data);
7905  }
7906 
7907  if (cut)
7908  {
7909  edit_state.CursorFollow = true;
7910  stb_textedit_cut(&edit_state, &edit_state.StbState);
7911  }
7912  }
7913  else if (is_shortcutkey_only && IsKeyPressedMap(ImGuiKey_V) && is_editable)
7914  {
7915  // Paste
7916  if (g.IO.GetClipboardTextFn)
7917  {
7918  if (const char* clipboard = g.IO.GetClipboardTextFn())
7919  {
7920  // Remove new-line from pasted buffer
7921  const int clipboard_len = (int)strlen(clipboard);
7922  ImWchar* clipboard_filtered = (ImWchar*)ImGui::MemAlloc((clipboard_len+1) * sizeof(ImWchar));
7923  int clipboard_filtered_len = 0;
7924  for (const char* s = clipboard; *s; )
7925  {
7926  unsigned int c;
7927  s += ImTextCharFromUtf8(&c, s, NULL);
7928  if (c == 0)
7929  break;
7930  if (c >= 0x10000 || !InputTextFilterCharacter(&c, flags, callback, user_data))
7931  continue;
7932  clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
7933  }
7934  clipboard_filtered[clipboard_filtered_len] = 0;
7935  if (clipboard_filtered_len > 0) // If everything was filtered, ignore the pasting operation
7936  {
7937  stb_textedit_paste(&edit_state, &edit_state.StbState, clipboard_filtered, clipboard_filtered_len);
7938  edit_state.CursorFollow = true;
7939  }
7940  ImGui::MemFree(clipboard_filtered);
7941  }
7942  }
7943  }
7944 
7945  if (cancel_edit)
7946  {
7947  // Restore initial value
7948  if (is_editable)
7949  {
7950  ImFormatString(buf, buf_size, "%s", edit_state.InitialText.Data);
7951  value_changed = true;
7952  }
7953  }
7954  else
7955  {
7956  // Apply new value immediately - copy modified buffer back
7957  // Note that as soon as the input box is active, the in-widget value gets priority over any underlying modification of the input buffer
7958  // FIXME: We actually always render 'buf' when calling DrawList->AddText, making the comment above incorrect.
7959  // FIXME-OPT: CPU waste to do this every time the widget is active, should mark dirty state from the stb_textedit callbacks.
7960  if (is_editable)
7961  {
7962  edit_state.TempTextBuffer.resize(edit_state.Text.Size * 4);
7963  ImTextStrToUtf8(edit_state.TempTextBuffer.Data, edit_state.TempTextBuffer.Size, edit_state.Text.Data, NULL);
7964  }
7965 
7966  // User callback
7967  if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackAlways)) != 0)
7968  {
7969  IM_ASSERT(callback != NULL);
7970 
7971  // The reason we specify the usage semantic (Completion/History) is that Completion needs to disable keyboard TABBING at the moment.
7972  ImGuiInputTextFlags event_flag = 0;
7973  ImGuiKey event_key = ImGuiKey_COUNT;
7974  if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && IsKeyPressedMap(ImGuiKey_Tab))
7975  {
7977  event_key = ImGuiKey_Tab;
7978  }
7979  else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_UpArrow))
7980  {
7982  event_key = ImGuiKey_UpArrow;
7983  }
7984  else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressedMap(ImGuiKey_DownArrow))
7985  {
7987  event_key = ImGuiKey_DownArrow;
7988  }
7989  else if (flags & ImGuiInputTextFlags_CallbackAlways)
7991 
7992  if (event_flag)
7993  {
7994  ImGuiTextEditCallbackData callback_data;
7995  memset(&callback_data, 0, sizeof(ImGuiTextEditCallbackData));
7996  callback_data.EventFlag = event_flag;
7997  callback_data.Flags = flags;
7998  callback_data.UserData = user_data;
7999  callback_data.ReadOnly = !is_editable;
8000 
8001  callback_data.EventKey = event_key;
8002  callback_data.Buf = edit_state.TempTextBuffer.Data;
8003  callback_data.BufTextLen = edit_state.CurLenA;
8004  callback_data.BufSize = edit_state.BufSizeA;
8005  callback_data.BufDirty = false;
8006 
8007  // We have to convert from wchar-positions to UTF-8-positions, which can be pretty slow (an incentive to ditch the ImWchar buffer, see https://github.com/nothings/stb/issues/188)
8008  ImWchar* text = edit_state.Text.Data;
8009  const int utf8_cursor_pos = callback_data.CursorPos = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.cursor);
8010  const int utf8_selection_start = callback_data.SelectionStart = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_start);
8011  const int utf8_selection_end = callback_data.SelectionEnd = ImTextCountUtf8BytesFromStr(text, text + edit_state.StbState.select_end);
8012 
8013  // Call user code
8014  callback(&callback_data);
8015 
8016  // Read back what user may have modified
8017  IM_ASSERT(callback_data.Buf == edit_state.TempTextBuffer.Data); // Invalid to modify those fields
8018  IM_ASSERT(callback_data.BufSize == edit_state.BufSizeA);
8019  IM_ASSERT(callback_data.Flags == flags);
8020  if (callback_data.CursorPos != utf8_cursor_pos) edit_state.StbState.cursor = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos);
8021  if (callback_data.SelectionStart != utf8_selection_start) edit_state.StbState.select_start = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart);
8022  if (callback_data.SelectionEnd != utf8_selection_end) edit_state.StbState.select_end = ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd);
8023  if (callback_data.BufDirty)
8024  {
8025  IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
8026  edit_state.CurLenW = ImTextStrFromUtf8(edit_state.Text.Data, edit_state.Text.Size, callback_data.Buf, NULL);
8027  edit_state.CurLenA = callback_data.BufTextLen; // Assume correct length and valid UTF-8 from user, saves us an extra strlen()
8028  edit_state.CursorAnimReset();
8029  }
8030  }
8031  }
8032 
8033  // Copy back to user buffer
8034  if (is_editable && strcmp(edit_state.TempTextBuffer.Data, buf) != 0)
8035  {
8036  ImFormatString(buf, buf_size, "%s", edit_state.TempTextBuffer.Data);
8037  value_changed = true;
8038  }
8039  }
8040  }
8041 
8042  if (!is_multiline)
8043  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
8044 
8045  // Render
8046  const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + size.x, frame_bb.Min.y + size.y); // Not using frame_bb.Max because we have adjusted size
8047  ImVec2 render_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
8048  ImVec2 text_size(0.f, 0.f);
8049  if (g.ActiveId == id || (edit_state.Id == id && is_multiline && g.ActiveId == draw_window->GetID("#SCROLLY")))
8050  {
8051  edit_state.CursorAnim += g.IO.DeltaTime;
8052 
8053  // We need to:
8054  // - Display the text (this can be more easily clipped)
8055  // - Handle scrolling, highlight selection, display cursor (those all requires some form of 1d->2d cursor position calculation)
8056  // - Measure text height (for scrollbar)
8057  // We are attempting to do most of that in **one main pass** to minimize the computation cost (non-negligible for large amount of text) + 2nd pass for selection rendering (we could merge them by an extra refactoring effort)
8058  const ImWchar* text_begin = edit_state.Text.Data;
8059  ImVec2 cursor_offset, select_start_offset;
8060 
8061  {
8062  // Count lines + find lines numbers straddling 'cursor' and 'select_start' position.
8063  const ImWchar* searches_input_ptr[2];
8064  searches_input_ptr[0] = text_begin + edit_state.StbState.cursor;
8065  searches_input_ptr[1] = NULL;
8066  int searches_remaining = 1;
8067  int searches_result_line_number[2] = { -1, -999 };
8068  if (edit_state.StbState.select_start != edit_state.StbState.select_end)
8069  {
8070  searches_input_ptr[1] = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
8071  searches_result_line_number[1] = -1;
8072  searches_remaining++;
8073  }
8074 
8075  // Iterate all lines to find our line numbers
8076  // In multi-line mode, we never exit the loop until all lines are counted, so add one extra to the searches_remaining counter.
8077  searches_remaining += is_multiline ? 1 : 0;
8078  int line_count = 0;
8079  for (const ImWchar* s = text_begin; *s != 0; s++)
8080  if (*s == '\n')
8081  {
8082  line_count++;
8083  if (searches_result_line_number[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_number[0] = line_count; if (--searches_remaining <= 0) break; }
8084  if (searches_result_line_number[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_number[1] = line_count; if (--searches_remaining <= 0) break; }
8085  }
8086  line_count++;
8087  if (searches_result_line_number[0] == -1) searches_result_line_number[0] = line_count;
8088  if (searches_result_line_number[1] == -1) searches_result_line_number[1] = line_count;
8089 
8090  // Calculate 2d position by finding the beginning of the line and measuring distance
8091  cursor_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
8092  cursor_offset.y = searches_result_line_number[0] * g.FontSize;
8093  if (searches_result_line_number[1] >= 0)
8094  {
8095  select_start_offset.x = InputTextCalcTextSizeW(ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
8096  select_start_offset.y = searches_result_line_number[1] * g.FontSize;
8097  }
8098 
8099  // Calculate text height
8100  if (is_multiline)
8101  text_size = ImVec2(size.x, line_count * g.FontSize);
8102  }
8103 
8104  // Scroll
8105  if (edit_state.CursorFollow)
8106  {
8107  // Horizontal scroll in chunks of quarter width
8109  {
8110  const float scroll_increment_x = size.x * 0.25f;
8111  if (cursor_offset.x < edit_state.ScrollX)
8112  edit_state.ScrollX = (float)(int)ImMax(0.0f, cursor_offset.x - scroll_increment_x);
8113  else if (cursor_offset.x - size.x >= edit_state.ScrollX)
8114  edit_state.ScrollX = (float)(int)(cursor_offset.x - size.x + scroll_increment_x);
8115  }
8116  else
8117  {
8118  edit_state.ScrollX = 0.0f;
8119  }
8120 
8121  // Vertical scroll
8122  if (is_multiline)
8123  {
8124  float scroll_y = draw_window->Scroll.y;
8125  if (cursor_offset.y - g.FontSize < scroll_y)
8126  scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
8127  else if (cursor_offset.y - size.y >= scroll_y)
8128  scroll_y = cursor_offset.y - size.y;
8129  draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // To avoid a frame of lag
8130  draw_window->Scroll.y = scroll_y;
8131  render_pos.y = draw_window->DC.CursorPos.y;
8132  }
8133  }
8134  edit_state.CursorFollow = false;
8135  const ImVec2 render_scroll = ImVec2(edit_state.ScrollX, 0.0f);
8136 
8137  // Draw selection
8138  if (edit_state.StbState.select_start != edit_state.StbState.select_end)
8139  {
8140  const ImWchar* text_selected_begin = text_begin + ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end);
8141  const ImWchar* text_selected_end = text_begin + ImMax(edit_state.StbState.select_start, edit_state.StbState.select_end);
8142 
8143  float bg_offy_up = is_multiline ? 0.0f : -1.0f; // FIXME: those offsets should be part of the style? they don't play so well with multi-line selection.
8144  float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
8146  ImVec2 rect_pos = render_pos + select_start_offset - render_scroll;
8147  for (const ImWchar* p = text_selected_begin; p < text_selected_end; )
8148  {
8149  if (rect_pos.y > clip_rect.w + g.FontSize)
8150  break;
8151  if (rect_pos.y < clip_rect.y)
8152  {
8153  while (p < text_selected_end)
8154  if (*p++ == '\n')
8155  break;
8156  }
8157  else
8158  {
8159  ImVec2 rect_size = InputTextCalcTextSizeW(p, text_selected_end, &p, NULL, true);
8160  if (rect_size.x <= 0.0f) rect_size.x = (float)(int)(g.Font->GetCharAdvance((unsigned short)' ') * 0.50f); // So we can see selected empty lines
8161  ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up - g.FontSize), rect_pos +ImVec2(rect_size.x, bg_offy_dn));
8162  rect.Clip(clip_rect);
8163  if (rect.Overlaps(clip_rect))
8164  draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
8165  }
8166  rect_pos.x = render_pos.x - render_scroll.x;
8167  rect_pos.y += g.FontSize;
8168  }
8169  }
8170 
8171  draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos - render_scroll, GetColorU32(ImGuiCol_Text), buf, buf+edit_state.CurLenA, 0.0f, is_multiline ? NULL : &clip_rect);
8172 
8173  // Draw blinking cursor
8174  bool cursor_is_visible = (g.InputTextState.CursorAnim <= 0.0f) || fmodf(g.InputTextState.CursorAnim, 1.20f) <= 0.80f;
8175  ImVec2 cursor_screen_pos = render_pos + cursor_offset - render_scroll;
8176  ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y-g.FontSize+0.5f, cursor_screen_pos.x+1.0f, cursor_screen_pos.y-1.5f);
8177  if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
8178  draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
8179 
8180  // Notify OS of text input position for advanced IME (-1 x offset so that Windows IME can cover our cursor. Bit of an extra nicety.)
8181  if (is_editable)
8182  g.OsImePosRequest = ImVec2(cursor_screen_pos.x - 1, cursor_screen_pos.y - g.FontSize);
8183  }
8184  else
8185  {
8186  // Render text only
8187  const char* buf_end = NULL;
8188  if (is_multiline)
8189  text_size = ImVec2(size.x, InputTextCalcTextLenAndLineCount(buf, &buf_end) * g.FontSize); // We don't need width
8190  draw_window->DrawList->AddText(g.Font, g.FontSize, render_pos, GetColorU32(ImGuiCol_Text), buf, buf_end, 0.0f, is_multiline ? NULL : &clip_rect);
8191  }
8192 
8193  if (is_multiline)
8194  {
8195  Dummy(text_size + ImVec2(0.0f, g.FontSize)); // Always add room to scroll an extra line
8196  EndChildFrame();
8197  EndGroup();
8198  }
8199 
8200  if (is_password)
8201  PopFont();
8202 
8203  // Log as text
8204  if (g.LogEnabled && !is_password)
8205  LogRenderedText(render_pos, buf, NULL);
8206 
8207  if (label_size.x > 0)
8208  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
8209 
8210  if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
8211  return enter_pressed;
8212  else
8213  return value_changed;
8214 }
8215 
8216 bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
8217 {
8218  IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()
8219  bool ret = InputTextEx(label, buf, (int)buf_size, ImVec2(0,0), flags, callback, user_data);
8220  return ret;
8221 }
8222 
8223 bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data)
8224 {
8225  bool ret = InputTextEx(label, buf, (int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
8226  return ret;
8227 }
8228 
8229 // NB: scalar_format here must be a simple "%xx" format string with no prefix/suffix (unlike the Drag/Slider functions "display_format" argument)
8230 bool ImGui::InputScalarEx(const char* label, ImGuiDataType data_type, void* data_ptr, void* step_ptr, void* step_fast_ptr, const char* scalar_format, ImGuiInputTextFlags extra_flags)
8231 {
8233  if (window->SkipItems)
8234  return false;
8235 
8236  ImGuiContext& g = *GImGui;
8237  const ImGuiStyle& style = g.Style;
8238  const ImVec2 label_size = CalcTextSize(label, NULL, true);
8239 
8240  BeginGroup();
8241  PushID(label);
8242  const ImVec2 button_sz = ImVec2(g.FontSize, g.FontSize) + style.FramePadding*2.0f;
8243  if (step_ptr)
8244  PushItemWidth(ImMax(1.0f, CalcItemWidth() - (button_sz.x + style.ItemInnerSpacing.x)*2));
8245 
8246  char buf[64];
8247  DataTypeFormatString(data_type, data_ptr, scalar_format, buf, IM_ARRAYSIZE(buf));
8248 
8249  bool value_changed = false;
8250  if (!(extra_flags & ImGuiInputTextFlags_CharsHexadecimal))
8251  extra_flags |= ImGuiInputTextFlags_CharsDecimal;
8252  extra_flags |= ImGuiInputTextFlags_AutoSelectAll;
8253  if (InputText("", buf, IM_ARRAYSIZE(buf), extra_flags))
8254  value_changed = DataTypeApplyOpFromText(buf, GImGui->InputTextState.InitialText.begin(), data_type, data_ptr, scalar_format);
8255 
8256  // Step buttons
8257  if (step_ptr)
8258  {
8259  PopItemWidth();
8260  SameLine(0, style.ItemInnerSpacing.x);
8262  {
8263  DataTypeApplyOp(data_type, '-', data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
8264  value_changed = true;
8265  }
8266  SameLine(0, style.ItemInnerSpacing.x);
8268  {
8269  DataTypeApplyOp(data_type, '+', data_ptr, g.IO.KeyCtrl && step_fast_ptr ? step_fast_ptr : step_ptr);
8270  value_changed = true;
8271  }
8272  }
8273  PopID();
8274 
8275  if (label_size.x > 0)
8276  {
8277  SameLine(0, style.ItemInnerSpacing.x);
8278  RenderText(ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + style.FramePadding.y), label);
8279  ItemSize(label_size, style.FramePadding.y);
8280  }
8281  EndGroup();
8282 
8283  return value_changed;
8284 }
8285 
8286 bool ImGui::InputFloat(const char* label, float* v, float step, float step_fast, int decimal_precision, ImGuiInputTextFlags extra_flags)
8287 {
8288  char display_format[16];
8289  if (decimal_precision < 0)
8290  strcpy(display_format, "%f"); // Ideally we'd have a minimum decimal precision of 1 to visually denote that this is a float, while hiding non-significant digits? %f doesn't have a minimum of 1
8291  else
8292  ImFormatString(display_format, 16, "%%.%df", decimal_precision);
8293  return InputScalarEx(label, ImGuiDataType_Float, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), display_format, extra_flags);
8294 }
8295 
8296 bool ImGui::InputInt(const char* label, int* v, int step, int step_fast, ImGuiInputTextFlags extra_flags)
8297 {
8298  // Hexadecimal input provided as a convenience but the flag name is awkward. Typically you'd use InputText() to parse your own data, if you want to handle prefixes.
8299  const char* scalar_format = (extra_flags & ImGuiInputTextFlags_CharsHexadecimal) ? "%08X" : "%d";
8300  return InputScalarEx(label, ImGuiDataType_Int, (void*)v, (void*)(step>0.0f ? &step : NULL), (void*)(step_fast>0.0f ? &step_fast : NULL), scalar_format, extra_flags);
8301 }
8302 
8303 bool ImGui::InputFloatN(const char* label, float* v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags)
8304 {
8306  if (window->SkipItems)
8307  return false;
8308 
8309  ImGuiContext& g = *GImGui;
8310  bool value_changed = false;
8311  BeginGroup();
8312  PushID(label);
8313  PushMultiItemsWidths(components);
8314  for (int i = 0; i < components; i++)
8315  {
8316  PushID(i);
8317  value_changed |= InputFloat("##v", &v[i], 0, 0, decimal_precision, extra_flags);
8319  PopID();
8320  PopItemWidth();
8321  }
8322  PopID();
8323 
8325  TextUnformatted(label, FindRenderedTextEnd(label));
8326  EndGroup();
8327 
8328  return value_changed;
8329 }
8330 
8331 bool ImGui::InputFloat2(const char* label, float v[2], int decimal_precision, ImGuiInputTextFlags extra_flags)
8332 {
8333  return InputFloatN(label, v, 2, decimal_precision, extra_flags);
8334 }
8335 
8336 bool ImGui::InputFloat3(const char* label, float v[3], int decimal_precision, ImGuiInputTextFlags extra_flags)
8337 {
8338  return InputFloatN(label, v, 3, decimal_precision, extra_flags);
8339 }
8340 
8341 bool ImGui::InputFloat4(const char* label, float v[4], int decimal_precision, ImGuiInputTextFlags extra_flags)
8342 {
8343  return InputFloatN(label, v, 4, decimal_precision, extra_flags);
8344 }
8345 
8346 bool ImGui::InputIntN(const char* label, int* v, int components, ImGuiInputTextFlags extra_flags)
8347 {
8349  if (window->SkipItems)
8350  return false;
8351 
8352  ImGuiContext& g = *GImGui;
8353  bool value_changed = false;
8354  BeginGroup();
8355  PushID(label);
8356  PushMultiItemsWidths(components);
8357  for (int i = 0; i < components; i++)
8358  {
8359  PushID(i);
8360  value_changed |= InputInt("##v", &v[i], 0, 0, extra_flags);
8362  PopID();
8363  PopItemWidth();
8364  }
8365  PopID();
8366 
8368  TextUnformatted(label, FindRenderedTextEnd(label));
8369  EndGroup();
8370 
8371  return value_changed;
8372 }
8373 
8374 bool ImGui::InputInt2(const char* label, int v[2], ImGuiInputTextFlags extra_flags)
8375 {
8376  return InputIntN(label, v, 2, extra_flags);
8377 }
8378 
8379 bool ImGui::InputInt3(const char* label, int v[3], ImGuiInputTextFlags extra_flags)
8380 {
8381  return InputIntN(label, v, 3, extra_flags);
8382 }
8383 
8384 bool ImGui::InputInt4(const char* label, int v[4], ImGuiInputTextFlags extra_flags)
8385 {
8386  return InputIntN(label, v, 4, extra_flags);
8387 }
8388 
8389 static bool Items_ArrayGetter(void* data, int idx, const char** out_text)
8390 {
8391  const char** items = (const char**)data;
8392  if (out_text)
8393  *out_text = items[idx];
8394  return true;
8395 }
8396 
8397 static bool Items_SingleStringGetter(void* data, int idx, const char** out_text)
8398 {
8399  // FIXME-OPT: we could pre-compute the indices to fasten this. But only 1 active combo means the waste is limited.
8400  const char* items_separated_by_zeros = (const char*)data;
8401  int items_count = 0;
8402  const char* p = items_separated_by_zeros;
8403  while (*p)
8404  {
8405  if (idx == items_count)
8406  break;
8407  p += strlen(p) + 1;
8408  items_count++;
8409  }
8410  if (!*p)
8411  return false;
8412  if (out_text)
8413  *out_text = p;
8414  return true;
8415 }
8416 
8417 // Combo box helper allowing to pass an array of strings.
8418 bool ImGui::Combo(const char* label, int* current_item, const char** items, int items_count, int height_in_items, bool show_arrow_down)
8419 {
8420  const bool value_changed = Combo(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_in_items);
8421  return value_changed;
8422 }
8423 
8424 // Combo box helper allowing to pass all items in a single string.
8425 bool ImGui::Combo(const char* label, int* current_item, const char* items_separated_by_zeros, int height_in_items, bool show_arrow_down)
8426 {
8427  int items_count = 0;
8428  const char* p = items_separated_by_zeros; // FIXME-OPT: Avoid computing this, or at least only when combo is open
8429  while (*p)
8430  {
8431  p += strlen(p) + 1;
8432  items_count++;
8433  }
8434  bool value_changed = Combo(label, current_item, Items_SingleStringGetter, (void*)items_separated_by_zeros, items_count, height_in_items, show_arrow_down);
8435  return value_changed;
8436 }
8437 
8438 // Combo box function.
8439 bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items, bool show_arrow_down)
8440 {
8442  if (window->SkipItems)
8443  return false;
8444 
8445  ImGuiContext& g = *GImGui;
8446  const ImGuiStyle& style = g.Style;
8447  const ImGuiID id = window->GetID(label);
8448  const float w = CalcItemWidth();
8449 
8450  const ImVec2 label_size = CalcTextSize(label, NULL, true);
8451  const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
8452  const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
8453  ItemSize(total_bb, style.FramePadding.y);
8454  if (!ItemAdd(total_bb, &id))
8455  return false;
8456 
8457  const float arrow_size = show_arrow_down ? (g.FontSize + style.FramePadding.x * 2.0f) : 0;
8458  const bool hovered = IsHovered(frame_bb, id);
8459  bool popup_open = IsPopupOpen(id);
8460  bool popup_opened_now = false;
8461 
8462  const ImRect value_bb(frame_bb.Min, frame_bb.Max - ImVec2(arrow_size, 0.0f));
8463  if (show_arrow_down)
8464  {
8465  RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
8466  RenderFrame(ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Min.y), frame_bb.Max, GetColorU32(popup_open || hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button), true, style.FrameRounding); // FIXME-ROUNDING
8467  RenderCollapseTriangle(ImVec2(frame_bb.Max.x - arrow_size, frame_bb.Min.y) + style.FramePadding, true);
8468  }
8469  if (*current_item >= 0 && *current_item < items_count)
8470  {
8471  const char* item_text;
8472  if (items_getter(data, *current_item, &item_text))
8473  RenderTextClipped(frame_bb.Min + style.FramePadding, value_bb.Max, item_text, NULL, NULL, ImGuiAlign_Center);
8474  }
8475 
8476  if (label_size.x > 0)
8477  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
8478 
8479  if (hovered)
8480  {
8481  SetHoveredID(id);
8482  if (g.IO.MouseClicked[0])
8483  {
8484  SetActiveID(0);
8485  if (IsPopupOpen(id))
8486  {
8487  ClosePopup(id);
8488  }
8489  else
8490  {
8491  FocusWindow(window);
8492  OpenPopup(label);
8493  popup_open = popup_opened_now = true;
8494  }
8495  }
8496  }
8497 
8498  bool value_changed = false;
8499  if (IsPopupOpen(id))
8500  {
8501  // Size default to hold ~7 items
8502  if (height_in_items < 0)
8503  height_in_items = 7;
8504 
8505  float popup_height = (label_size.y + style.ItemSpacing.y) * ImMin(items_count, height_in_items) + (style.FramePadding.y * 3);
8506  float popup_y1 = frame_bb.Max.y;
8507  float popup_y2 = ImClamp(popup_y1 + popup_height, popup_y1, g.IO.DisplaySize.y - style.DisplaySafeAreaPadding.y);
8508  if ((popup_y2 - popup_y1) < ImMin(popup_height, frame_bb.Min.y - style.DisplaySafeAreaPadding.y))
8509  {
8510  // Position our combo ABOVE because there's more space to fit! (FIXME: Handle in Begin() or use a shared helper. We have similar code in Begin() for popup placement)
8511  popup_y1 = ImClamp(frame_bb.Min.y - popup_height, style.DisplaySafeAreaPadding.y, frame_bb.Min.y);
8512  popup_y2 = frame_bb.Min.y;
8513  }
8514  ImRect popup_rect(ImVec2(frame_bb.Min.x, popup_y1), ImVec2(frame_bb.Max.x, popup_y2));
8515  SetNextWindowPos(popup_rect.Min);
8516  SetNextWindowSize(popup_rect.GetSize());
8518 
8520  if (BeginPopupEx(label, flags))
8521  {
8522  // Display items
8523  Spacing();
8524  for (int i = 0; i < items_count; i++)
8525  {
8526  PushID((void*)(intptr_t)i);
8527  const bool item_selected = (i == *current_item);
8528  const char* item_text;
8529  if (!items_getter(data, i, &item_text))
8530  item_text = "*Unknown item*";
8531  if (Selectable(item_text, item_selected))
8532  {
8533  SetActiveID(0);
8534  value_changed = true;
8535  *current_item = i;
8536  }
8537  if (item_selected && popup_opened_now)
8538  SetScrollHere();
8539  PopID();
8540  }
8541  EndPopup();
8542  }
8543  PopStyleVar();
8544  }
8545  return value_changed;
8546 }
8547 
8548 // Tip: pass an empty label (e.g. "##dummy") then you can use the space to draw other text or image.
8549 // But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID.
8550 bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
8551 {
8553  if (window->SkipItems)
8554  return false;
8555 
8556  ImGuiContext& g = *GImGui;
8557  const ImGuiStyle& style = g.Style;
8558 
8559  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
8560  PopClipRect();
8561 
8562  ImGuiID id = window->GetID(label);
8563  ImVec2 label_size = CalcTextSize(label, NULL, true);
8564  ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
8565  ImVec2 pos = window->DC.CursorPos;
8566  pos.y += window->DC.CurrentLineTextBaseOffset;
8567  ImRect bb(pos, pos + size);
8568  ItemSize(bb);
8569 
8570  // Fill horizontal space.
8571  ImVec2 window_padding = window->WindowPadding;
8573  float w_draw = ImMax(label_size.x, window->Pos.x + max_x - window_padding.x - window->DC.CursorPos.x);
8574  ImVec2 size_draw((size_arg.x != 0 && !(flags & ImGuiSelectableFlags_DrawFillAvailWidth)) ? size_arg.x : w_draw, size_arg.y != 0.0f ? size_arg.y : size.y);
8575  ImRect bb_with_spacing(pos, pos + size_draw);
8576  if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_DrawFillAvailWidth))
8577  bb_with_spacing.Max.x += window_padding.x;
8578 
8579  // Selectables are tightly packed together, we extend the box to cover spacing between selectable.
8580  float spacing_L = (float)(int)(style.ItemSpacing.x * 0.5f);
8581  float spacing_U = (float)(int)(style.ItemSpacing.y * 0.5f);
8582  float spacing_R = style.ItemSpacing.x - spacing_L;
8583  float spacing_D = style.ItemSpacing.y - spacing_U;
8584  bb_with_spacing.Min.x -= spacing_L;
8585  bb_with_spacing.Min.y -= spacing_U;
8586  bb_with_spacing.Max.x += spacing_R;
8587  bb_with_spacing.Max.y += spacing_D;
8588  if (!ItemAdd(bb_with_spacing, &id))
8589  {
8590  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
8592  return false;
8593  }
8594 
8595  ImGuiButtonFlags button_flags = 0;
8596  if (flags & ImGuiSelectableFlags_Menu) button_flags |= ImGuiButtonFlags_PressedOnClick;
8598  if (flags & ImGuiSelectableFlags_Disabled) button_flags |= ImGuiButtonFlags_Disabled;
8600  bool hovered, held;
8601  bool pressed = ButtonBehavior(bb_with_spacing, id, &hovered, &held, button_flags);
8602  if (flags & ImGuiSelectableFlags_Disabled)
8603  selected = false;
8604 
8605  // Render
8606  if (hovered || selected)
8607  {
8608  const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
8609  RenderFrame(bb_with_spacing.Min, bb_with_spacing.Max, col, false, 0.0f);
8610  }
8611 
8612  if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.ColumnsCount > 1)
8613  {
8615  bb_with_spacing.Max.x -= (GetContentRegionMax().x - max_x);
8616  }
8617 
8618  if (flags & ImGuiSelectableFlags_Disabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
8619  if (hovered || selected) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextSelectedBg]);
8620  RenderTextClipped(bb.Min, bb_with_spacing.Max, label, NULL, &label_size);
8621  if (hovered || selected) PopStyleColor();
8622  if (flags & ImGuiSelectableFlags_Disabled) PopStyleColor();
8623 
8624  // Automatically close popups
8625  if (pressed && !(flags & ImGuiSelectableFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
8627  return pressed;
8628 }
8629 
8630 bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
8631 {
8632  if (Selectable(label, *p_selected, flags, size_arg))
8633  {
8634  *p_selected = !*p_selected;
8635  return true;
8636  }
8637  return false;
8638 }
8639 
8640 // Helper to calculate the size of a listbox and display a label on the right.
8641 // Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an empty label "##empty"
8642 bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
8643 {
8645  if (window->SkipItems)
8646  return false;
8647 
8648  const ImGuiStyle& style = GetStyle();
8649  const ImGuiID id = GetID(label);
8650  const ImVec2 label_size = CalcTextSize(label, NULL, true);
8651 
8652  // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
8654  ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));
8655  ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
8656  ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
8657  window->DC.LastItemRect = bb;
8658 
8659  BeginGroup();
8660  if (label_size.x > 0)
8661  RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
8662 
8663  BeginChildFrame(id, frame_bb.GetSize());
8664  return true;
8665 }
8666 
8667 bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items)
8668 {
8669  // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
8670  // However we don't add +0.40f if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size.
8671  // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution.
8672  if (height_in_items < 0)
8673  height_in_items = ImMin(items_count, 7);
8674  float height_in_items_f = height_in_items < items_count ? (height_in_items + 0.40f) : (height_in_items + 0.00f);
8675 
8676  // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild().
8677  ImVec2 size;
8678  size.x = 0.0f;
8679  size.y = GetTextLineHeightWithSpacing() * height_in_items_f + GetStyle().ItemSpacing.y;
8680  return ListBoxHeader(label, size);
8681 }
8682 
8684 {
8685  ImGuiWindow* parent_window = GetParentWindow();
8686  const ImRect bb = parent_window->DC.LastItemRect;
8687  const ImGuiStyle& style = GetStyle();
8688 
8689  EndChildFrame();
8690 
8691  // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect)
8692  // We call SameLine() to restore DC.CurrentLine* data
8693  SameLine();
8694  parent_window->DC.CursorPos = bb.Min;
8695  ItemSize(bb, style.FramePadding.y);
8696  EndGroup();
8697 }
8698 
8699 bool ImGui::ListBox(const char* label, int* current_item, const char** items, int items_count, int height_items)
8700 {
8701  const bool value_changed = ListBox(label, current_item, Items_ArrayGetter, (void*)items, items_count, height_items);
8702  return value_changed;
8703 }
8704 
8705 bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items)
8706 {
8707  if (!ListBoxHeader(label, items_count, height_in_items))
8708  return false;
8709 
8710  // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper.
8711  bool value_changed = false;
8712  ImGuiListClipper clipper(items_count, GetTextLineHeightWithSpacing());
8713  while (clipper.Step())
8714  for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
8715  {
8716  const bool item_selected = (i == *current_item);
8717  const char* item_text;
8718  if (!items_getter(data, i, &item_text))
8719  item_text = "*Unknown item*";
8720 
8721  PushID(i);
8722  if (Selectable(item_text, item_selected))
8723  {
8724  *current_item = i;
8725  value_changed = true;
8726  }
8727  PopID();
8728  }
8729  ListBoxFooter();
8730  return value_changed;
8731 }
8732 
8733 bool ImGui::MenuItem(const char* label, const char* shortcut, bool selected, bool enabled)
8734 {
8736  if (window->SkipItems)
8737  return false;
8738 
8739  ImGuiContext& g = *GImGui;
8740  ImVec2 pos = window->DC.CursorPos;
8741  ImVec2 label_size = CalcTextSize(label, NULL, true);
8742  ImVec2 shortcut_size = shortcut ? CalcTextSize(shortcut, NULL) : ImVec2(0.0f, 0.0f);
8743  float w = window->MenuColumns.DeclColumns(label_size.x, shortcut_size.x, (float)(int)(g.FontSize * 1.20f)); // Feedback for next frame
8744  float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
8745 
8747  if (shortcut_size.x > 0.0f)
8748  {
8750  RenderText(pos + ImVec2(window->MenuColumns.Pos[1] + extra_w, 0.0f), shortcut, NULL, false);
8751  PopStyleColor();
8752  }
8753 
8754  if (selected)
8755  RenderCheckMark(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled));
8756 
8757  return pressed;
8758 }
8759 
8760 bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled)
8761 {
8762  if (MenuItem(label, shortcut, p_selected ? *p_selected : false, enabled))
8763  {
8764  if (p_selected)
8765  *p_selected = !*p_selected;
8766  return true;
8767  }
8768  return false;
8769 }
8770 
8772 {
8773  ImGuiContext& g = *GImGui;
8774  SetNextWindowPos(ImVec2(0.0f, 0.0f));
8779  || !BeginMenuBar())
8780  {
8781  End();
8782  PopStyleVar(2);
8783  return false;
8784  }
8786  return true;
8787 }
8788 
8790 {
8791  EndMenuBar();
8792  End();
8793  PopStyleVar(2);
8794 }
8795 
8797 {
8799  if (window->SkipItems)
8800  return false;
8801  if (!(window->Flags & ImGuiWindowFlags_MenuBar))
8802  return false;
8803 
8804  IM_ASSERT(!window->DC.MenuBarAppending);
8805  BeginGroup(); // Save position
8806  PushID("##menubar");
8807  ImRect rect = window->MenuBarRect();
8808  PushClipRect(ImVec2(ImFloor(rect.Min.x+0.5f), ImFloor(rect.Min.y + window->BorderSize + 0.5f)), ImVec2(ImFloor(rect.Max.x+0.5f), ImFloor(rect.Max.y+0.5f)), false);
8809  window->DC.CursorPos = ImVec2(rect.Min.x + window->DC.MenuBarOffsetX, rect.Min.y);// + g.Style.FramePadding.y);
8811  window->DC.MenuBarAppending = true;
8813  return true;
8814 }
8815 
8817 {
8819  if (window->SkipItems)
8820  return;
8821 
8823  IM_ASSERT(window->DC.MenuBarAppending);
8824  PopClipRect();
8825  PopID();
8826  window->DC.MenuBarOffsetX = window->DC.CursorPos.x - window->MenuBarRect().Min.x;
8827  window->DC.GroupStack.back().AdvanceCursor = false;
8828  EndGroup();
8830  window->DC.MenuBarAppending = false;
8831 }
8832 
8833 bool ImGui::BeginMenu(const char* label, bool enabled)
8834 {
8836  if (window->SkipItems)
8837  return false;
8838 
8839  ImGuiContext& g = *GImGui;
8840  const ImGuiStyle& style = g.Style;
8841  const ImGuiID id = window->GetID(label);
8842 
8843  ImVec2 label_size = CalcTextSize(label, NULL, true);
8844  ImGuiWindow* backed_focused_window = g.FocusedWindow;
8845 
8846  bool pressed;
8847  bool menu_is_open = IsPopupOpen(id);
8848  bool menuset_is_open = !(window->Flags & ImGuiWindowFlags_Popup) && (g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentMenuSet == window->GetID("##menus"));
8849  if (menuset_is_open)
8850  g.FocusedWindow = window;
8851 
8852  ImVec2 popup_pos, pos = window->DC.CursorPos;
8853  if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
8854  {
8855  popup_pos = ImVec2(pos.x - window->WindowPadding.x, pos.y - style.FramePadding.y + window->MenuBarHeight());
8856  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
8858  float w = label_size.x;
8859  pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_Menu | ImGuiSelectableFlags_DontClosePopups | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
8860  PopStyleVar();
8861  SameLine();
8862  window->DC.CursorPos.x += (float)(int)(style.ItemSpacing.x * 0.5f);
8863  }
8864  else
8865  {
8866  popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
8867  float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame
8868  float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
8871  RenderCollapseTriangle(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.20f, 0.0f), false);
8872  if (!enabled) PopStyleColor();
8873  }
8874 
8875  bool hovered = enabled && IsHovered(window->DC.LastItemRect, id);
8876  if (menuset_is_open)
8877  g.FocusedWindow = backed_focused_window;
8878 
8879  bool want_open = false, want_close = false;
8881  {
8882  // Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
8883  bool moving_within_opened_triangle = false;
8884  if (g.HoveredWindow == window && g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].ParentWindow == window)
8885  {
8886  if (ImGuiWindow* next_window = g.OpenPopupStack[g.CurrentPopupStack.Size].Window)
8887  {
8888  ImRect next_window_rect = next_window->Rect();
8889  ImVec2 ta = g.IO.MousePos - g.IO.MouseDelta;
8890  ImVec2 tb = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR();
8891  ImVec2 tc = (window->Pos.x < next_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR();
8892  float extra = ImClamp(fabsf(ta.x - tb.x) * 0.30f, 5.0f, 30.0f); // add a bit of extra slack.
8893  ta.x += (window->Pos.x < next_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues
8894  tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -100.0f); // triangle is maximum 200 high to limit the slope and the bias toward large sub-menus // FIXME: Multiply by fb_scale?
8895  tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +100.0f);
8896  moving_within_opened_triangle = ImIsPointInTriangle(g.IO.MousePos, ta, tb, tc);
8897  //window->DrawList->PushClipRectFullScreen(); window->DrawList->AddTriangleFilled(ta, tb, tc, moving_within_opened_triangle ? 0x80008000 : 0x80000080); window->DrawList->PopClipRect(); // Debug
8898  }
8899  }
8900 
8901  want_close = (menu_is_open && !hovered && g.HoveredWindow == window && g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrame != id && !moving_within_opened_triangle);
8902  want_open = (!menu_is_open && hovered && !moving_within_opened_triangle) || (!menu_is_open && hovered && pressed);
8903  }
8904  else if (menu_is_open && pressed && menuset_is_open) // menu-bar: click open menu to close
8905  {
8906  want_close = true;
8907  want_open = menu_is_open = false;
8908  }
8909  else if (pressed || (hovered && menuset_is_open && !menu_is_open)) // menu-bar: first click to open, then hover to open others
8910  want_open = true;
8911  if (!enabled) // explicitly close if an open menu becomes disabled, facilitate users code a lot in pattern such as 'if (BeginMenu("options", has_object)) { ..use object.. }'
8912  want_close = true;
8913  if (want_close && IsPopupOpen(id))
8915 
8916  if (!menu_is_open && want_open && g.OpenPopupStack.Size > g.CurrentPopupStack.Size)
8917  {
8918  // Don't recycle same menu level in the same frame, first close the other menu and yield for a frame.
8919  OpenPopup(label);
8920  return false;
8921  }
8922 
8923  menu_is_open |= want_open;
8924  if (want_open)
8925  OpenPopup(label);
8926 
8927  if (menu_is_open)
8928  {
8931  menu_is_open = BeginPopupEx(label, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
8932  }
8933 
8934  return menu_is_open;
8935 }
8936 
8938 {
8939  EndPopup();
8940 }
8941 
8942 // A little colored square. Return true when clicked.
8943 // FIXME: May want to display/ignore the alpha component in the color display? Yet show it in the tooltip.
8944 bool ImGui::ColorButton(const ImVec4& col, bool small_height, bool outline_border)
8945 {
8947  if (window->SkipItems)
8948  return false;
8949 
8950  ImGuiContext& g = *GImGui;
8951  const ImGuiStyle& style = g.Style;
8952  const ImGuiID id = window->GetID("#colorbutton");
8953  const float square_size = g.FontSize;
8954  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(square_size + style.FramePadding.y*2, square_size + (small_height ? 0 : style.FramePadding.y*2)));
8955  ItemSize(bb, small_height ? 0.0f : style.FramePadding.y);
8956  if (!ItemAdd(bb, &id))
8957  return false;
8958 
8959  bool hovered, held;
8960  bool pressed = ButtonBehavior(bb, id, &hovered, &held);
8961  RenderFrame(bb.Min, bb.Max, GetColorU32(col), outline_border, style.FrameRounding);
8962 
8963  if (hovered)
8964  SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col.x, col.y, col.z, col.w, IM_F32_TO_INT8(col.x), IM_F32_TO_INT8(col.y), IM_F32_TO_INT8(col.z), IM_F32_TO_INT8(col.z));
8965 
8966  return pressed;
8967 }
8968 
8969 bool ImGui::ColorEdit3(const char* label, float col[3])
8970 {
8971  float col4[4];
8972  col4[0] = col[0];
8973  col4[1] = col[1];
8974  col4[2] = col[2];
8975  col4[3] = 1.0f;
8976  const bool value_changed = ColorEdit4(label, col4, false);
8977  col[0] = col4[0];
8978  col[1] = col4[1];
8979  col[2] = col4[2];
8980  return value_changed;
8981 }
8982 
8983 // Edit colors components (each component in 0.0f..1.0f range
8984 // Use CTRL-Click to input value and TAB to go to next item.
8985 bool ImGui::ColorEdit4(const char* label, float col[4], bool alpha)
8986 {
8988  if (window->SkipItems)
8989  return false;
8990 
8991  ImGuiContext& g = *GImGui;
8992  const ImGuiStyle& style = g.Style;
8993  const ImGuiID id = window->GetID(label);
8994  const float w_full = CalcItemWidth();
8995  const float square_sz = (g.FontSize + style.FramePadding.y * 2.0f);
8996 
8997  ImGuiColorEditMode edit_mode = window->DC.ColorEditMode;
8999  edit_mode = g.ColorEditModeStorage.GetInt(id, 0) % 3;
9000 
9001  float f[4] = { col[0], col[1], col[2], col[3] };
9002  if (edit_mode == ImGuiColorEditMode_HSV)
9003  ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
9004 
9005  int i[4] = { IM_F32_TO_INT8(f[0]), IM_F32_TO_INT8(f[1]), IM_F32_TO_INT8(f[2]), IM_F32_TO_INT8(f[3]) };
9006 
9007  int components = alpha ? 4 : 3;
9008  bool value_changed = false;
9009 
9010  BeginGroup();
9011  PushID(label);
9012 
9013  const bool hsv = (edit_mode == 1);
9014  switch (edit_mode)
9015  {
9018  {
9019  // RGB/HSV 0..255 Sliders
9020  const float w_items_all = w_full - (square_sz + style.ItemInnerSpacing.x);
9021  const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
9022  const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
9023 
9024  const bool hide_prefix = (w_item_one <= CalcTextSize("M:999").x);
9025  const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
9026  const char* fmt_table[3][4] =
9027  {
9028  { "%3.0f", "%3.0f", "%3.0f", "%3.0f" },
9029  { "R:%3.0f", "G:%3.0f", "B:%3.0f", "A:%3.0f" },
9030  { "H:%3.0f", "S:%3.0f", "V:%3.0f", "A:%3.0f" }
9031  };
9032  const char** fmt = hide_prefix ? fmt_table[0] : hsv ? fmt_table[2] : fmt_table[1];
9033 
9034  PushItemWidth(w_item_one);
9035  for (int n = 0; n < components; n++)
9036  {
9037  if (n > 0)
9038  SameLine(0, style.ItemInnerSpacing.x);
9039  if (n + 1 == components)
9040  PushItemWidth(w_item_last);
9041  value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, 255, fmt[n]);
9042  }
9043  PopItemWidth();
9044  PopItemWidth();
9045  }
9046  break;
9048  {
9049  // RGB Hexadecimal Input
9050  const float w_slider_all = w_full - square_sz;
9051  char buf[64];
9052  if (alpha)
9053  ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", i[0], i[1], i[2], i[3]);
9054  else
9055  ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", i[0], i[1], i[2]);
9056  PushItemWidth(w_slider_all - style.ItemInnerSpacing.x);
9058  {
9059  value_changed |= true;
9060  char* p = buf;
9061  while (*p == '#' || ImCharIsSpace(*p))
9062  p++;
9063  i[0] = i[1] = i[2] = i[3] = 0;
9064  if (alpha)
9065  sscanf(p, "%02X%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2], (unsigned int*)&i[3]); // Treat at unsigned (%X is unsigned)
9066  else
9067  sscanf(p, "%02X%02X%02X", (unsigned int*)&i[0], (unsigned int*)&i[1], (unsigned int*)&i[2]);
9068  }
9069  PopItemWidth();
9070  }
9071  break;
9072  }
9073 
9074  SameLine(0, style.ItemInnerSpacing.x);
9075 
9076  const ImVec4 col_display(col[0], col[1], col[2], 1.0f);
9077  if (ColorButton(col_display))
9078  g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away!
9079 
9080  // Recreate our own tooltip over's ColorButton() one because we want to display correct alpha here
9081  if (IsItemHovered())
9082  SetTooltip("Color:\n(%.2f,%.2f,%.2f,%.2f)\n#%02X%02X%02X%02X", col[0], col[1], col[2], col[3], IM_F32_TO_INT8(col[0]), IM_F32_TO_INT8(col[1]), IM_F32_TO_INT8(col[2]), IM_F32_TO_INT8(col[3]));
9083 
9085  {
9086  SameLine(0, style.ItemInnerSpacing.x);
9087  const char* button_titles[3] = { "RGB", "HSV", "HEX" };
9088  if (ButtonEx(button_titles[edit_mode], ImVec2(0,0), ImGuiButtonFlags_DontClosePopups))
9089  g.ColorEditModeStorage.SetInt(id, (edit_mode + 1) % 3); // Don't set local copy of 'edit_mode' right away!
9090  }
9091 
9092  const char* label_display_end = FindRenderedTextEnd(label);
9093  if (label != label_display_end)
9094  {
9096  TextUnformatted(label, label_display_end);
9097  }
9098 
9099  // Convert back
9100  for (int n = 0; n < 4; n++)
9101  f[n] = i[n] / 255.0f;
9102  if (edit_mode == 1)
9103  ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
9104 
9105  if (value_changed)
9106  {
9107  col[0] = f[0];
9108  col[1] = f[1];
9109  col[2] = f[2];
9110  if (alpha)
9111  col[3] = f[3];
9112  }
9113 
9114  PopID();
9115  EndGroup();
9116 
9117  return value_changed;
9118 }
9119 
9121 {
9123  window->DC.ColorEditMode = mode;
9124 }
9125 
9126 // Horizontal separating line.
9128 {
9130  if (window->SkipItems)
9131  return;
9132 
9133  if (window->DC.ColumnsCount > 1)
9134  PopClipRect();
9135 
9136  float x1 = window->Pos.x;
9137  float x2 = window->Pos.x + window->Size.x;
9138  if (!window->DC.GroupStack.empty())
9139  x1 += window->DC.IndentX;
9140 
9141  const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y));
9142  ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit // FIXME: Height should be 1.0f not 0.0f ?
9143  if (!ItemAdd(bb, NULL))
9144  {
9145  if (window->DC.ColumnsCount > 1)
9147  return;
9148  }
9149 
9150  window->DrawList->AddLine(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border));
9151 
9152  ImGuiContext& g = *GImGui;
9153  if (g.LogEnabled)
9154  LogText(IM_NEWLINE "--------------------------------");
9155 
9156  if (window->DC.ColumnsCount > 1)
9157  {
9159  window->DC.ColumnsCellMinY = window->DC.CursorPos.y;
9160  }
9161 }
9162 
9164 {
9166  if (window->SkipItems)
9167  return;
9168  ItemSize(ImVec2(0,0));
9169 }
9170 
9172 {
9174  if (window->SkipItems)
9175  return;
9176 
9177  const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
9178  ItemSize(bb);
9179  ItemAdd(bb, NULL);
9180 }
9181 
9183 {
9185  return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
9186 }
9187 
9188 // Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
9190 {
9192 
9193  window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
9194  ImGuiGroupData& group_data = window->DC.GroupStack.back();
9195  group_data.BackupCursorPos = window->DC.CursorPos;
9196  group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
9197  group_data.BackupIndentX = window->DC.IndentX;
9198  group_data.BackupCurrentLineHeight = window->DC.CurrentLineHeight;
9200  group_data.BackupLogLinePosY = window->DC.LogLinePosY;
9201  group_data.AdvanceCursor = true;
9202 
9203  window->DC.IndentX = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffsetX;
9204  window->DC.CursorMaxPos = window->DC.CursorPos;
9205  window->DC.CurrentLineHeight = 0.0f;
9206  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
9207 }
9208 
9210 {
9212  ImGuiStyle& style = GetStyle();
9213 
9214  IM_ASSERT(!window->DC.GroupStack.empty()); // Mismatched BeginGroup()/EndGroup() calls
9215 
9216  ImGuiGroupData& group_data = window->DC.GroupStack.back();
9217 
9218  ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos);
9219  group_bb.Max.y -= style.ItemSpacing.y; // Cancel out last vertical spacing because we are adding one ourselves.
9220  group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
9221 
9222  window->DC.CursorPos = group_data.BackupCursorPos;
9223  window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
9224  window->DC.CurrentLineHeight = group_data.BackupCurrentLineHeight;
9225  window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
9226  window->DC.IndentX = group_data.BackupIndentX;
9227  window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
9228 
9229  if (group_data.AdvanceCursor)
9230  {
9231  window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
9232  ItemSize(group_bb.GetSize(), group_data.BackupCurrentLineTextBaseOffset);
9233  ItemAdd(group_bb, NULL);
9234  }
9235 
9236  window->DC.GroupStack.pop_back();
9237 
9238  //window->DrawList->AddRect(group_bb.Min, group_bb.Max, 0xFFFF00FF); // Debug
9239 }
9240 
9241 // Gets back to previous line and continue with horizontal layout
9242 // pos_x == 0 : follow on previous item
9243 // pos_x != 0 : align to specified column
9244 // spacing_w < 0 : use default spacing if column_x==0, no spacing if column_x!=0
9245 // spacing_w >= 0 : enforce spacing
9246 void ImGui::SameLine(float pos_x, float spacing_w)
9247 {
9249  if (window->SkipItems)
9250  return;
9251 
9252  ImGuiContext& g = *GImGui;
9253  if (pos_x != 0.0f)
9254  {
9255  if (spacing_w < 0.0f) spacing_w = 0.0f;
9256  window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w;
9257  window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
9258  }
9259  else
9260  {
9261  if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
9262  window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
9263  window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
9264  }
9265  window->DC.CurrentLineHeight = window->DC.PrevLineHeight;
9267 }
9268 
9270 {
9272  if (window->SkipItems)
9273  return;
9274  if (window->DC.CurrentLineHeight > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height.
9275  ItemSize(ImVec2(0,0));
9276  else
9277  ItemSize(ImVec2(0.0f, GImGui->FontSize));
9278 }
9279 
9281 {
9283  if (window->SkipItems)
9284  return;
9285 
9286  ImGuiContext& g = *GImGui;
9287  if (window->DC.ColumnsCount > 1)
9288  {
9289  PopItemWidth();
9290  PopClipRect();
9291 
9292  window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
9293  if (++window->DC.ColumnsCurrent < window->DC.ColumnsCount)
9294  {
9295  // Columns 1+ cancel out IndentX
9296  window->DC.ColumnsOffsetX = GetColumnOffset(window->DC.ColumnsCurrent) - window->DC.IndentX + g.Style.ItemSpacing.x;
9297  window->DrawList->ChannelsSetCurrent(window->DC.ColumnsCurrent);
9298  }
9299  else
9300  {
9301  window->DC.ColumnsCurrent = 0;
9302  window->DC.ColumnsOffsetX = 0.0f;
9303  window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY;
9304  window->DrawList->ChannelsSetCurrent(0);
9305  }
9306  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
9307  window->DC.CursorPos.y = window->DC.ColumnsCellMinY;
9308  window->DC.CurrentLineHeight = 0.0f;
9309  window->DC.CurrentLineTextBaseOffset = 0.0f;
9310 
9312  PushItemWidth(GetColumnWidth() * 0.65f); // FIXME: Move on columns setup
9313  }
9314 }
9315 
9317 {
9319  return window->DC.ColumnsCurrent;
9320 }
9321 
9323 {
9325  return window->DC.ColumnsCount;
9326 }
9327 
9328 static float GetDraggedColumnOffset(int column_index)
9329 {
9330  // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
9331  // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
9332  ImGuiContext& g = *GImGui;
9334  IM_ASSERT(column_index > 0); // We cannot drag column 0. If you get this assert you may have a conflict between the ID of your columns and another widgets.
9335  IM_ASSERT(g.ActiveId == window->DC.ColumnsSetID + ImGuiID(column_index));
9336 
9337  float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x - window->Pos.x;
9339 
9340  return (float)(int)x;
9341 }
9342 
9343 float ImGui::GetColumnOffset(int column_index)
9344 {
9345  ImGuiContext& g = *GImGui;
9347  if (column_index < 0)
9348  column_index = window->DC.ColumnsCurrent;
9349 
9350  if (g.ActiveId)
9351  {
9352  const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index);
9353  if (g.ActiveId == column_id)
9354  return GetDraggedColumnOffset(column_index);
9355  }
9356 
9357  IM_ASSERT(column_index < window->DC.ColumnsData.Size);
9358  const float t = window->DC.ColumnsData[column_index].OffsetNorm;
9359  const float x_offset = window->DC.ColumnsMinX + t * (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
9360  return (float)(int)x_offset;
9361 }
9362 
9363 void ImGui::SetColumnOffset(int column_index, float offset)
9364 {
9366  if (column_index < 0)
9367  column_index = window->DC.ColumnsCurrent;
9368 
9369  IM_ASSERT(column_index < window->DC.ColumnsData.Size);
9370  const float t = (offset - window->DC.ColumnsMinX) / (window->DC.ColumnsMaxX - window->DC.ColumnsMinX);
9371  window->DC.ColumnsData[column_index].OffsetNorm = t;
9372 
9373  const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index);
9374  window->DC.StateStorage->SetFloat(column_id, t);
9375 }
9376 
9377 float ImGui::GetColumnWidth(int column_index)
9378 {
9380  if (column_index < 0)
9381  column_index = window->DC.ColumnsCurrent;
9382 
9383  float w = GetColumnOffset(column_index+1) - GetColumnOffset(column_index);
9384  return w;
9385 }
9386 
9387 static void PushColumnClipRect(int column_index)
9388 {
9390  if (column_index < 0)
9391  column_index = window->DC.ColumnsCurrent;
9392 
9393  float x1 = ImFloor(0.5f + window->Pos.x + ImGui::GetColumnOffset(column_index) - 1.0f);
9394  float x2 = ImFloor(0.5f + window->Pos.x + ImGui::GetColumnOffset(column_index+1) - 1.0f);
9395  ImGui::PushClipRect(ImVec2(x1,-FLT_MAX), ImVec2(x2,+FLT_MAX), true);
9396 }
9397 
9398 void ImGui::Columns(int columns_count, const char* id, bool border)
9399 {
9400  ImGuiContext& g = *GImGui;
9402  IM_ASSERT(columns_count >= 1);
9403 
9404  if (window->DC.ColumnsCount != 1)
9405  {
9406  if (window->DC.ColumnsCurrent != 0)
9407  ItemSize(ImVec2(0,0)); // Advance to column 0
9408  PopItemWidth();
9409  PopClipRect();
9410  window->DrawList->ChannelsMerge();
9411 
9412  window->DC.ColumnsCellMaxY = ImMax(window->DC.ColumnsCellMaxY, window->DC.CursorPos.y);
9413  window->DC.CursorPos.y = window->DC.ColumnsCellMaxY;
9414  }
9415 
9416  // Draw columns borders and handle resize at the time of "closing" a columns set
9417  if (window->DC.ColumnsCount != columns_count && window->DC.ColumnsCount != 1 && window->DC.ColumnsShowBorders && !window->SkipItems)
9418  {
9419  const float y1 = window->DC.ColumnsStartPosY;
9420  const float y2 = window->DC.CursorPos.y;
9421  for (int i = 1; i < window->DC.ColumnsCount; i++)
9422  {
9423  float x = window->Pos.x + GetColumnOffset(i);
9424  const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(i);
9425  const ImRect column_rect(ImVec2(x-4,y1),ImVec2(x+4,y2));
9426  if (IsClippedEx(column_rect, &column_id, false))
9427  continue;
9428 
9429  bool hovered, held;
9430  ButtonBehavior(column_rect, column_id, &hovered, &held);
9431  if (hovered || held)
9433 
9434  // Draw before resize so our items positioning are in sync with the line being drawn
9436  const float xi = (float)(int)x;
9437  window->DrawList->AddLine(ImVec2(xi, y1+1.0f), ImVec2(xi, y2), col);
9438 
9439  if (held)
9440  {
9442  g.ActiveIdClickOffset.x -= 4; // Store from center of column line
9444  SetColumnOffset(i, x);
9445  }
9446  }
9447  }
9448 
9449  // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
9450  // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
9451  PushID(0x11223347 + (id ? 0 : columns_count));
9452  window->DC.ColumnsSetID = window->GetID(id ? id : "columns");
9453  PopID();
9454 
9455  // Set state for first column
9456  window->DC.ColumnsCurrent = 0;
9457  window->DC.ColumnsCount = columns_count;
9458  window->DC.ColumnsShowBorders = border;
9459 
9460  const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : window->Size.x;
9461  window->DC.ColumnsMinX = window->DC.IndentX; // Lock our horizontal range
9462  window->DC.ColumnsMaxX = content_region_width - window->Scroll.x /*- ((window->Flags & ImGuiWindowFlags_NoScrollbar) ? 0 : g.Style.ScrollbarSize)*/;// - window->WindowPadding().x;
9463  window->DC.ColumnsStartPosY = window->DC.CursorPos.y;
9464  window->DC.ColumnsCellMinY = window->DC.ColumnsCellMaxY = window->DC.CursorPos.y;
9465  window->DC.ColumnsOffsetX = 0.0f;
9466  window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX);
9467 
9468  if (window->DC.ColumnsCount != 1)
9469  {
9470  // Cache column offsets
9471  window->DC.ColumnsData.resize(columns_count + 1);
9472  for (int column_index = 0; column_index < columns_count + 1; column_index++)
9473  {
9474  const ImGuiID column_id = window->DC.ColumnsSetID + ImGuiID(column_index);
9475  KeepAliveID(column_id);
9476  const float default_t = column_index / (float)window->DC.ColumnsCount;
9477  const float t = window->DC.StateStorage->GetFloat(column_id, default_t); // Cheaply store our floating point value inside the integer (could store an union into the map?)
9478  window->DC.ColumnsData[column_index].OffsetNorm = t;
9479  }
9480  window->DrawList->ChannelsSplit(window->DC.ColumnsCount);
9482  PushItemWidth(GetColumnWidth() * 0.65f);
9483  }
9484  else
9485  {
9486  window->DC.ColumnsData.resize(0);
9487  }
9488 }
9489 
9490 void ImGui::Indent(float indent_w)
9491 {
9492  ImGuiContext& g = *GImGui;
9494  window->DC.IndentX += (indent_w > 0.0f) ? indent_w : g.Style.IndentSpacing;
9495  window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
9496 }
9497 
9498 void ImGui::Unindent(float indent_w)
9499 {
9500  ImGuiContext& g = *GImGui;
9502  window->DC.IndentX -= (indent_w > 0.0f) ? indent_w : g.Style.IndentSpacing;
9503  window->DC.CursorPos.x = window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX;
9504 }
9505 
9506 void ImGui::TreePush(const char* str_id)
9507 {
9509  Indent();
9510  window->DC.TreeDepth++;
9511  PushID(str_id ? str_id : "#TreePush");
9512 }
9513 
9514 void ImGui::TreePush(const void* ptr_id)
9515 {
9517  Indent();
9518  window->DC.TreeDepth++;
9519  PushID(ptr_id ? ptr_id : (const void*)"#TreePush");
9520 }
9521 
9523 {
9525  Indent();
9526  window->DC.TreeDepth++;
9527  window->IDStack.push_back(id);
9528 }
9529 
9531 {
9533  Unindent();
9534  window->DC.TreeDepth--;
9535  PopID();
9536 }
9537 
9538 void ImGui::Value(const char* prefix, bool b)
9539 {
9540  Text("%s: %s", prefix, (b ? "true" : "false"));
9541 }
9542 
9543 void ImGui::Value(const char* prefix, int v)
9544 {
9545  Text("%s: %d", prefix, v);
9546 }
9547 
9548 void ImGui::Value(const char* prefix, unsigned int v)
9549 {
9550  Text("%s: %d", prefix, v);
9551 }
9552 
9553 void ImGui::Value(const char* prefix, float v, const char* float_format)
9554 {
9555  if (float_format)
9556  {
9557  char fmt[64];
9558  ImFormatString(fmt, IM_ARRAYSIZE(fmt), "%%s: %s", float_format);
9559  Text(fmt, prefix, v);
9560  }
9561  else
9562  {
9563  Text("%s: %.3f", prefix, v);
9564  }
9565 }
9566 
9567 // FIXME: May want to remove those helpers?
9568 void ImGui::ValueColor(const char* prefix, const ImVec4& v)
9569 {
9570  Text("%s: (%.2f,%.2f,%.2f,%.2f)", prefix, v.x, v.y, v.z, v.w);
9571  SameLine();
9572  ColorButton(v, true);
9573 }
9574 
9575 void ImGui::ValueColor(const char* prefix, unsigned int v)
9576 {
9577  Text("%s: %08X", prefix, v);
9578  SameLine();
9579 
9580  ImVec4 col;
9581  col.x = (float)((v >> 0) & 0xFF) / 255.0f;
9582  col.y = (float)((v >> 8) & 0xFF) / 255.0f;
9583  col.z = (float)((v >> 16) & 0xFF) / 255.0f;
9584  col.w = (float)((v >> 24) & 0xFF) / 255.0f;
9585  ColorButton(col, true);
9586 }
9587 
9588 //-----------------------------------------------------------------------------
9589 // PLATFORM DEPENDANT HELPERS
9590 //-----------------------------------------------------------------------------
9591 
9592 #if defined(_WIN32) && !defined(_WINDOWS_) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS))
9593 #undef WIN32_LEAN_AND_MEAN
9594 #define WIN32_LEAN_AND_MEAN
9595 #include <windows.h>
9596 #endif
9597 
9598 // Win32 API clipboard implementation
9599 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS)
9600 
9601 #ifdef _MSC_VER
9602 #pragma comment(lib, "user32")
9603 #endif
9604 
9605 static const char* GetClipboardTextFn_DefaultImpl()
9606 {
9607  static char* buf_local = NULL;
9608  if (buf_local)
9609  {
9610  ImGui::MemFree(buf_local);
9611  buf_local = NULL;
9612  }
9613  if (!OpenClipboard(NULL))
9614  return NULL;
9615  HANDLE wbuf_handle = GetClipboardData(CF_UNICODETEXT);
9616  if (wbuf_handle == NULL)
9617  return NULL;
9618  if (ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle))
9619  {
9620  int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
9621  buf_local = (char*)ImGui::MemAlloc(buf_len * sizeof(char));
9622  ImTextStrToUtf8(buf_local, buf_len, wbuf_global, NULL);
9623  }
9624  GlobalUnlock(wbuf_handle);
9625  CloseClipboard();
9626  return buf_local;
9627 }
9628 
9629 static void SetClipboardTextFn_DefaultImpl(const char* text)
9630 {
9631  if (!OpenClipboard(NULL))
9632  return;
9633 
9634  const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
9635  HGLOBAL wbuf_handle = GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
9636  if (wbuf_handle == NULL)
9637  return;
9638  ImWchar* wbuf_global = (ImWchar*)GlobalLock(wbuf_handle);
9639  ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL);
9640  GlobalUnlock(wbuf_handle);
9641  EmptyClipboard();
9642  SetClipboardData(CF_UNICODETEXT, wbuf_handle);
9643  CloseClipboard();
9644 }
9645 
9646 #else
9647 
9648 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
9650 {
9651  return GImGui->PrivateClipboard;
9652 }
9653 
9654 // Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
9655 static void SetClipboardTextFn_DefaultImpl(const char* text)
9656 {
9657  ImGuiContext& g = *GImGui;
9658  if (g.PrivateClipboard)
9659  {
9661  g.PrivateClipboard = NULL;
9662  }
9663  const char* text_end = text + strlen(text);
9664  g.PrivateClipboard = (char*)ImGui::MemAlloc((size_t)(text_end - text) + 1);
9665  memcpy(g.PrivateClipboard, text, (size_t)(text_end - text));
9666  g.PrivateClipboard[(int)(text_end - text)] = 0;
9667 }
9668 
9669 #endif
9670 
9671 // Win32 API IME support (for Asian languages, etc.)
9672 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS)
9673 
9674 #include <imm.h>
9675 #ifdef _MSC_VER
9676 #pragma comment(lib, "imm32")
9677 #endif
9678 
9679 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
9680 {
9681  // Notify OS Input Method Editor of text input position
9682  if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle)
9683  if (HIMC himc = ImmGetContext(hwnd))
9684  {
9685  COMPOSITIONFORM cf;
9686  cf.ptCurrentPos.x = x;
9687  cf.ptCurrentPos.y = y;
9688  cf.dwStyle = CFS_FORCE_POSITION;
9689  ImmSetCompositionWindow(himc, &cf);
9690  }
9691 }
9692 
9693 #else
9694 
9695 static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
9696 
9697 #endif
9698 
9699 //-----------------------------------------------------------------------------
9700 // HELP
9701 //-----------------------------------------------------------------------------
9702 
9703 void ImGui::ShowMetricsWindow(bool* p_open)
9704 {
9705  if (ImGui::Begin("ImGui Metrics", p_open))
9706  {
9707  ImGui::Text("ImGui %s", ImGui::GetVersion());
9708  ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
9709  ImGui::Text("%d vertices, %d indices (%d triangles)", ImGui::GetIO().MetricsRenderVertices, ImGui::GetIO().MetricsRenderIndices, ImGui::GetIO().MetricsRenderIndices / 3);
9710  ImGui::Text("%d allocations", ImGui::GetIO().MetricsAllocs);
9711  static bool show_clip_rects = true;
9712  ImGui::Checkbox("Show clipping rectangles when hovering a ImDrawCmd", &show_clip_rects);
9713  ImGui::Separator();
9714 
9715  struct Funcs
9716  {
9717  static void NodeDrawList(ImDrawList* draw_list, const char* label)
9718  {
9719  bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size);
9720  if (draw_list == ImGui::GetWindowDrawList())
9721  {
9722  ImGui::SameLine();
9723  ImGui::TextColored(ImColor(255,100,100), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
9724  if (node_open) ImGui::TreePop();
9725  return;
9726  }
9727  if (!node_open)
9728  return;
9729 
9730  ImDrawList* overlay_draw_list = &GImGui->OverlayDrawList; // Render additional visuals into the top-most draw list
9731  overlay_draw_list->PushClipRectFullScreen();
9732  int elem_offset = 0;
9733  for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
9734  {
9735  if (pcmd->UserCallback)
9736  {
9737  ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
9738  continue;
9739  }
9740  ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
9741  bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %-4d %s vtx, tex = %p, clip_rect = (%.0f,%.0f)..(%.0f,%.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
9742  if (show_clip_rects && ImGui::IsItemHovered())
9743  {
9744  ImRect clip_rect = pcmd->ClipRect;
9745  ImRect vtxs_rect;
9746  for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
9747  vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
9748  clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255));
9749  vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255));
9750  }
9751  if (!pcmd_node_open)
9752  continue;
9753  ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
9754  while (clipper.Step())
9755  for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
9756  {
9757  char buf[300], *buf_p = buf;
9758  ImVec2 triangles_pos[3];
9759  for (int n = 0; n < 3; n++, vtx_i++)
9760  {
9761  ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i];
9762  triangles_pos[n] = v.pos;
9763  buf_p += sprintf(buf_p, "%s %04d { pos = (%8.2f,%8.2f), uv = (%.6f,%.6f), col = %08X }\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
9764  }
9765  ImGui::Selectable(buf, false);
9766  if (ImGui::IsItemHovered())
9767  overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f, false); // Add triangle without AA, more readable for large-thin triangle
9768  }
9769  ImGui::TreePop();
9770  }
9771  overlay_draw_list->PopClipRect();
9772  ImGui::TreePop();
9773  }
9774 
9775  static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
9776  {
9777  if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size))
9778  return;
9779  for (int i = 0; i < windows.Size; i++)
9780  Funcs::NodeWindow(windows[i], "Window");
9781  ImGui::TreePop();
9782  }
9783 
9784  static void NodeWindow(ImGuiWindow* window, const char* label)
9785  {
9786  if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window))
9787  return;
9788  NodeDrawList(window->DrawList, "DrawList");
9789  if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
9790  if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
9791  ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));
9792  ImGui::TreePop();
9793  }
9794  };
9795 
9796  ImGuiContext& g = *GImGui; // Access private state
9797  Funcs::NodeWindows(g.Windows, "Windows");
9798  if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.RenderDrawLists[0].Size))
9799  {
9800  for (int i = 0; i < g.RenderDrawLists[0].Size; i++)
9801  Funcs::NodeDrawList(g.RenderDrawLists[0][i], "DrawList");
9802  ImGui::TreePop();
9803  }
9804  if (ImGui::TreeNode("Popups", "Open Popups Stack (%d)", g.OpenPopupStack.Size))
9805  {
9806  for (int i = 0; i < g.OpenPopupStack.Size; i++)
9807  {
9808  ImGuiWindow* window = g.OpenPopupStack[i].Window;
9809  ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupID, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : "");
9810  }
9811  ImGui::TreePop();
9812  }
9813  if (ImGui::TreeNode("Basic state"))
9814  {
9815  ImGui::Text("FocusedWindow: '%s'", g.FocusedWindow ? g.FocusedWindow->Name : "NULL");
9816  ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
9817  ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
9818  ImGui::Text("HoveredID: 0x%08X/0x%08X", g.HoveredId, g.HoveredIdPreviousFrame); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
9819  ImGui::Text("ActiveID: 0x%08X/0x%08X", g.ActiveId, g.ActiveIdPreviousFrame);
9820  ImGui::TreePop();
9821  }
9822  }
9823  ImGui::End();
9824 }
9825 
9826 //-----------------------------------------------------------------------------
9827 
9828 // Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
9829 // Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github.
9830 #ifdef IMGUI_INCLUDE_IMGUI_USER_INL
9831 #include "imgui_user.inl"
9832 #endif
9833 
9834 //-----------------------------------------------------------------------------
~ImGuiWindow()
Definition: imgui.cpp:1742
ImGuiCol Col
void Add(const ImVec2 &rhs)
static bool InputTextFilterCharacter(unsigned int *p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void *user_data)
Definition: imgui.cpp:7597
IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val)
Definition: imgui.cpp:4650
static void Scrollbar(ImGuiWindow *window, bool horizontal)
Definition: imgui.cpp:4356
ImRect SetNextWindowSizeConstraintRect
static int ImMax(int lhs, int rhs)
IMGUI_API void RenderTextClipped(const ImVec2 &pos_min, const ImVec2 &pos_max, const char *text, const char *text_end, const ImVec2 *text_size_if_known, ImGuiAlign align=ImGuiAlign_Default, const ImVec2 *clip_min=NULL, const ImVec2 *clip_max=NULL)
Definition: imgui.cpp:2826
ImGuiSetCond SetNextTreeNodeOpenCond
ImVec2 BackupCursorPos
IMGUI_API bool FocusableItemRegister(ImGuiWindow *window, bool is_active, bool tab_stop=true)
Definition: imgui.cpp:1892
IMGUI_API void Image(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1), const ImVec4 &border_col=ImVec4(0, 0, 0, 0))
Definition: imgui.cpp:5635
ImGuiWindow * RootNonPopupWindow
int FocusIdxTabRequestNext
float Framerate
Definition: imgui.h:863
int FocusIdxTabCounter
IMGUI_API float GetCursorPosX()
Definition: imgui.cpp:5082
IMGUI_API void AddRectFilled(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners=0x0F)
Definition: imgui_draw.cpp:814
bool HasSelection() const
void PathStroke(ImU32 col, bool closed, float thickness=1.0f)
Definition: imgui.h:1264
IMGUI_API bool IsKeyPressed(int key_index, bool repeat=true)
Definition: imgui.cpp:3068
IMGUI_API float * GetFloatRef(ImGuiID key, float default_val=0.0f)
Definition: imgui.cpp:1364
static int ChildWindowComparer(const void *lhs, const void *rhs)
Definition: imgui.cpp:2460
IMGUI_API ImVec2 GetCursorStartPos()
Definition: imgui.cpp:5115
void * TexID
Definition: imgui.h:1375
unsigned int ImU32
Definition: imgui.h:63
IMGUI_API void RenderText(ImVec2 pos, const char *text, const char *text_end=NULL, bool hide_text_after_hash=true)
Definition: imgui.cpp:2781
IMGUI_API bool IsMouseReleased(int button)
Definition: imgui.cpp:3121
GLuint GLuint end
bool MouseDrawCursor
Definition: imgui.h:843
IMGUI_API bool BeginChildFrame(ImGuiID id, const ImVec2 &size, ImGuiWindowFlags extra_flags=0)
Definition: imgui.cpp:3601
GLboolean GLboolean GLboolean b
static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
Definition: imgui.cpp:666
GLboolean GLboolean g
ImDrawList ** CmdLists
Definition: imgui.h:1300
ImRect WindowRectClipped
void Clip(const ImRect &clip)
static const char * GetClipboardTextFn_DefaultImpl()
Definition: imgui.cpp:9649
GLint y
IMGUI_API bool RadioButton(const char *label, bool active)
Definition: imgui.cpp:7332
#define STB_TEXTEDIT_K_LINESTART
Definition: imgui.cpp:7533
IMGUI_API void OpenPopupEx(const char *str_id, bool reopen_existing)
Definition: imgui.cpp:3327
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiSetCond cond=0)
Definition: imgui.cpp:4887
IMGUI_API ImVec2 GetCursorPos()
Definition: imgui.cpp:5076
static ImVector< ImGuiStorage::Pair >::iterator LowerBound(ImVector< ImGuiStorage::Pair > &data, ImU32 key)
Definition: imgui.cpp:1299
void(* MemFreeFn)(void *ptr)
Definition: imgui.h:829
IMGUI_API bool BeginPopupContextItem(const char *str_id, int mouse_button=1)
Definition: imgui.cpp:3507
ImDrawIdx * _IdxWritePtr
Definition: imgui.h:1225
IMGUI_API void SetTooltip(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:3288
IMGUI_API void BulletText(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:6191
IMGUI_API void SetScrollFromPosY(float pos_y, float center_y_ratio=0.5f)
Definition: imgui.cpp:5169
static ImGuiWindow * FindHoveredWindow(ImVec2 pos, bool excluding_childs)
Definition: imgui.cpp:2993
typedef void(APIENTRY *GLDEBUGPROC)(GLenum source
static ImWchar STB_TEXTEDIT_NEWLINE
Definition: imgui.cpp:7465
ImVec2 GetCenter() const
GLuint const GLchar * name
bool ActiveIdIsJustActivated
const char * LogFilename
Definition: imgui.h:790
IMGUI_API float GetFontSize()
Definition: imgui.cpp:5056
IMGUI_API void AddCircle(const ImVec2 &centre, float radius, ImU32 col, int num_segments=12, float thickness=1.0f)
Definition: imgui_draw.cpp:891
ImVec2 GetBR() const
ImRect TitleBarRect() const
bool IsLoaded() const
Definition: imgui.h:1427
int ImTextCharFromUtf8(unsigned int *out_char, const char *in_text, const char *in_text_end)
Definition: imgui.cpp:1010
IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2 &size, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), int frame_padding=-1, const ImVec4 &bg_col=ImVec4(0, 0, 0, 0), const ImVec4 &tint_col=ImVec4(1, 1, 1, 1))
Definition: imgui.cpp:5663
bool DoubleClickSelectsWord
Definition: imgui.h:809
IMGUI_API void SetVoidPtr(ImGuiID key, void *val)
Definition: imgui.cpp:1408
float ModalWindowDarkeningRatio
ImGuiWindow * ParentWindow
void PathFill(ImU32 col)
Definition: imgui.h:1263
ImGuiWindow * FocusedWindow
IMGUI_API void PopTextureID()
Definition: imgui_draw.cpp:265
IMGUI_API bool TreeNodeExV(const char *str_id, ImGuiTreeNodeFlags flags, const char *fmt, va_list args)
Definition: imgui.cpp:6002
ImVec2 ActiveIdClickOffset
IMGUI_API void ProgressBar(float fraction, const ImVec2 &size_arg=ImVec2(-1, 0), const char *overlay=NULL)
Definition: imgui.cpp:7234
IMGUI_API float RoundScalar(float value, int decimal_precision)
Definition: imgui.cpp:6358
ImVec2 MousePos
Definition: imgui.h:840
IMGUI_API void AddInputCharacter(ImWchar c)
Definition: imgui.cpp:843
IMGUI_API void LabelTextV(const char *label, const char *fmt, va_list args)
Definition: imgui.cpp:5398
static void SetWindowScrollY(ImGuiWindow *window, float new_scroll_y)
Definition: imgui.cpp:4792
ImVector< ImWchar > Text
static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
Definition: imgui.cpp:1614
GLdouble s
IMGUI_API ImGuiStorage * GetStateStorage()
Definition: imgui.cpp:5201
IMGUI_API void PopClipRect()
Definition: imgui_draw.cpp:252
void OnKeyPressed(int key)
Definition: imgui.cpp:7550
void DeleteChars(int pos, int bytes_count)
Definition: imgui.cpp:7560
IMGUI_API void Clear()
Definition: imgui.cpp:1293
IMGUI_API bool InputTextMultiline(const char *label, char *buf, size_t buf_size, const ImVec2 &size=ImVec2(0, 0), ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:8223
#define IM_F32_TO_INT8(_VAL)
Definition: imgui.cpp:867
IMGUI_API const char * FindRenderedTextEnd(const char *text, const char *text_end=NULL)
Definition: imgui.cpp:2697
IMGUI_API void Icon(const char *icon)
Definition: imgui.cpp:5218
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiSetCond cond=0)
Definition: imgui.cpp:4967
IMGUI_API bool IsRootWindowFocused()
Definition: imgui.cpp:4755
IMGUI_API void ChannelsSetCurrent(int channel_index)
Definition: imgui_draw.cpp:339
IMGUI_API bool IsWindowFocused()
Definition: imgui.cpp:4749
static void stb_textedit_initialize_state(STB_TexteditState *state, int is_single_line)
Definition: imgui.cpp:1314
IMGUI_API bool InputInt3(const char *label, int v[3], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8379
IMGUI_API void SetCursorPos(const ImVec2 &local_pos)
Definition: imgui.cpp:5094
GLfloat GLfloat p
Definition: glext.h:12687
ImGuiLayoutType LayoutType
const GLfloat * m
Definition: glext.h:6814
static bool is_separator(unsigned int c)
Definition: imgui.cpp:7479
IMGUI_API void split(char separator, ImVector< TextRange > &out)
Definition: imgui.cpp:1456
void resize(int new_size)
Definition: imgui.h:931
ImGuiSetCond SetNextWindowPosCond
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition: glext.h:9721
int ImTextStrToUtf8(char *buf, int buf_size, const ImWchar *in_text, const ImWchar *in_text_end)
Definition: imgui.cpp:1149
ImVec2 SetNextWindowContentSizeVal
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:10806
float FontWindowScale
IMGUI_API void ValueColor(const char *prefix, const ImVec4 &v)
Definition: imgui.cpp:9568
static GLFWwindow * window
Definition: joysticks.c:55
int ImStrlenW(const ImWchar *str)
Definition: imgui.cpp:905
Definition: imgui.h:88
IMGUI_API bool IsMouseClicked(int button, bool repeat=false)
Definition: imgui.cpp:3103
IMGUI_API bool IsItemClicked(int mouse_button=0)
Definition: imgui.cpp:3223
bool SetNextWindowCollapsedVal
float CurveTessellationTol
Definition: imgui.h:772
GLdouble GLdouble GLdouble y2
IMGUI_API void SetWindowPos(const ImVec2 &pos, ImGuiSetCond cond=0)
Definition: imgui.cpp:4815
bool ActiveIdAllowOverlap
IMGUI_API void PopTextWrapPos()
Definition: imgui.cpp:4592
ImGuiStorage ColorEditModeStorage
int CaptureKeyboardNextFrame
ImVec2 ScrollbarClickDeltaToGrabCenter
ImVec2 DisplaySize
Definition: imgui.h:786
static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
Definition: imgui.cpp:450
ImGuiInputTextFlags Flags
Definition: imgui.h:1066
IMGUI_API void CalcListClipping(int items_count, float items_height, int *out_items_display_start, int *out_items_display_end)
Definition: imgui.cpp:2965
IMGUI_API bool IsMouseDown(int button)
Definition: imgui.cpp:3096
bool MouseClicked[5]
Definition: imgui.h:875
int FramerateSecPerFrameIdx
IMGUI_API void ClearFreeMemory()
Definition: imgui_draw.cpp:134
IMGUI_API void AddInputCharactersUTF8(const char *utf8_chars)
Definition: imgui.cpp:853
static ImFontAtlas GImDefaultFontAtlas
Definition: imgui.cpp:715
ImVec2 ItemSpacing
Definition: imgui.h:759
IMGUI_API ImVec2 GetItemRectMin()
Definition: imgui.cpp:3255
IMGUI_API bool IsItemActive()
Definition: imgui.cpp:3212
static bool Items_SingleStringGetter(void *data, int idx, const char **out_text)
Definition: imgui.cpp:8397
IMGUI_API void * MemAlloc(size_t sz)
Definition: imgui.cpp:1955
GLfloat value
IMGUI_API void SetHoveredID(ImGuiID id)
Definition: imgui.cpp:1795
ImGuiID HoveredId
bool Valid
Definition: imgui.h:1299
ImDrawList OverlayDrawList
int FocusIdxAllRequestCurrent
IMGUI_API void SetNextWindowFocus()
Definition: imgui.cpp:4974
IMGUI_API ImVec2 GetMouseDragDelta(int button=0, float lock_threshold=-1.0f)
Definition: imgui.cpp:3160
static float * GetStyleVarFloatAddr(ImGuiStyleVar idx)
Definition: imgui.cpp:4621
IMGUI_API void NewFrame()
Definition: imgui.cpp:2040
IMGUI_API const char * GetStyleColName(ImGuiCol idx)
Definition: imgui.cpp:4690
IMGUI_API bool IsRootWindowOrAnyChildHovered()
Definition: imgui.cpp:4767
int ImGuiColorEditMode
Definition: imgui.h:74
float CalcExtraSpace(float avail_w)
Definition: imgui.cpp:1605
static const textual_icon repeat
Definition: model-views.h:242
static bool IsWindowContentHoverable(ImGuiWindow *window)
Definition: imgui.cpp:5431
int ImGuiTreeNodeFlags
Definition: imgui.h:80
IMGUI_API void SetNextWindowPos(const ImVec2 &pos, ImGuiSetCond cond=0)
Definition: imgui.cpp:4923
IMGUI_API void EndTooltip()
Definition: imgui.cpp:3310
IMGUI_API bool InputInt4(const char *label, int v[4], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8384
ImVector< ImGuiIniData > Settings
IMGUI_API void LogButtons()
Definition: imgui.cpp:5780
IMGUI_API int GetKeyIndex(ImGuiKey key)
Definition: imgui.cpp:3055
IMGUI_API bool BeginPopupContextWindow(bool also_over_items=true, const char *str_id=NULL, int mouse_button=1)
Definition: imgui.cpp:3514
ImGuiID MovedWindowMoveId
bool MouseReleased[5]
Definition: imgui.h:879
float TitleBarHeight() const
IMGUI_API void CaptureMouseFromApp(bool capture=true)
Definition: imgui.cpp:3195
static const char * log_to_file
Definition: model-views.h:161
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition: glext.h:9721
IMGUI_API void PushTextureID(const ImTextureID &texture_id)
Definition: imgui_draw.cpp:259
int size() const
Definition: imgui.h:1006
ImVec2 ItemInnerSpacing
Definition: imgui.h:760
int(* ImGuiTextEditCallback)(ImGuiTextEditCallbackData *data)
Definition: imgui.h:81
float Descent
Definition: imgui.h:1417
IMGUI_API void SetScrollHere(float center_y_ratio=0.5f)
Definition: imgui.cpp:5181
float FramerateSecPerFrameAccum
float MouseClickedTime[5]
Definition: imgui.h:877
IMGUI_API void PopAllowKeyboardFocus()
Definition: imgui.cpp:4564
IMGUI_API bool SmallButton(const char *label)
Definition: imgui.cpp:5579
static ImWchar STB_TEXTEDIT_GETCHAR(const STB_TEXTEDIT_STRING *obj, int idx)
Definition: imgui.cpp:7462
IMGUI_API bool IsMouseHoveringRect(const ImVec2 &r_min, const ImVec2 &r_max, bool clip=true)
Definition: imgui.cpp:3017
ImGuiSetCond SetNextWindowContentSizeCond
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)
Definition: imgui.cpp:7413
IMGUI_API void PushClipRect(const ImVec2 &clip_rect_min, const ImVec2 &clip_rect_max, bool intersect_with_current_clip_rect)
Definition: imgui.cpp:2533
GLenum GLenum dst
Definition: glext.h:1751
GLenum GLuint GLint GLint layer
IMGUI_API bool BeginChild(const char *str_id, const ImVec2 &size=ImVec2(0, 0), bool border=false, ImGuiWindowFlags extra_flags=0)
Definition: imgui.cpp:3531
IMGUI_API void PathArcToFast(const ImVec2 &centre, float radius, int a_min_of_12, int a_max_of_12)
Definition: imgui_draw.cpp:676
static void LoadSettings()
Definition: imgui.cpp:2364
IMGUI_API void ShowMetricsWindow(bool *p_open=NULL)
Definition: imgui.cpp:9703
bool Draw(const char *label="Filter (inc,-exc)", float width=0.0f)
Definition: imgui.cpp:1444
static ImGuiWindow * CreateNewWindow(const char *name, ImVec2 size, ImGuiWindowFlags flags)
Definition: imgui.cpp:3672
static void SetCurrentFont(ImFont *font)
Definition: imgui.cpp:4528
int CmdListsCount
Definition: imgui.h:1301
IMGUI_API void BeginTooltip()
Definition: imgui.cpp:3304
IMGUI_API void BulletTextV(const char *fmt, va_list args)
Definition: imgui.cpp:6167
IMGUI_API bool TreeNodeEx(const char *label, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:5993
static int STB_TEXTEDIT_STRINGLEN(const STB_TEXTEDIT_STRING *obj)
Definition: imgui.cpp:7461
ImVec2 SetNextWindowSizeVal
IMGUI_API bool IsMouseHoveringAnyWindow()
Definition: imgui.cpp:3038
float KeysDownDuration[512]
Definition: imgui.h:884
ImVec2 DisplayVisibleMax
Definition: imgui.h:804
#define STB_TEXTEDIT_K_UNDO
Definition: imgui.cpp:7539
bool ShortcutsUseSuperKey
Definition: imgui.h:808
void swap(ImVector< T > &rhs)
Definition: imgui.h:927
GLdouble GLdouble GLdouble w
ImGuiContext * GImGui
Definition: imgui.cpp:719
IMGUI_API bool * GetBoolRef(ImGuiID key, bool default_val=false)
Definition: imgui.cpp:1359
static void ApplySizeFullWithConstraint(ImGuiWindow *window, ImVec2 new_size)
Definition: imgui.cpp:3738
static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int key)
Definition: imgui.cpp:697
static void SetWindowSize(ImGuiWindow *window, const ImVec2 &size, ImGuiSetCond cond)
Definition: imgui.cpp:4834
d
Definition: rmse.py:171
IMGUI_API void Indent(float indent_w=0.0f)
Definition: imgui.cpp:9490
#define STB_TEXTEDIT_K_TEXTEND
Definition: imgui.cpp:7536
IMGUI_API void AddTriangleFilled(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, ImU32 col)
Definition: imgui_draw.cpp:880
float BackupCurrentLineTextBaseOffset
IMGUI_API void PushTextWrapPos(float wrap_pos_x=0.0f)
Definition: imgui.cpp:4585
IMGUI_API void PushButtonRepeat(bool repeat)
Definition: imgui.cpp:4571
ImVec2 SetNextWindowPosVal
static float ImFloor(float f)
ImGuiStorage StateStorage
ImVec2 MouseClickedPos[5]
Definition: imgui.h:876
GLfloat v0
IMGUI_API void ResetMouseDragDelta(int button=0)
Definition: imgui.cpp:3172
IMGUI_API bool IsWindowHovered()
Definition: imgui.cpp:4743
ImVector< ImDrawList * > RenderDrawLists[3]
bool MouseDoubleClicked[5]
Definition: imgui.h:878
ImVec2 DisplayVisibleMin
Definition: imgui.h:803
int ImStricmp(const char *str1, const char *str2)
Definition: imgui.cpp:884
ImGuiAlign WindowTitleAlign
Definition: imgui.h:755
char * ImStrdup(const char *str)
Definition: imgui.cpp:898
GLenum src
Definition: glext.h:1751
IMGUI_API bool IsItemHoveredRect()
Definition: imgui.cpp:3206
int MetricsAllocs
Definition: imgui.h:864
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:1960
bool SetNextWindowFocus
ImGuiPlotType
IMGUI_API ImGuiMouseCursor GetMouseCursor()
Definition: imgui.cpp:3180
GLdouble n
Definition: glext.h:1966
IMGUI_API float GetColumnOffset(int column_index=-1)
Definition: imgui.cpp:9343
GLhandleARB obj
Definition: glext.h:4157
ImGuiColorEditMode ColorEditMode
const char * begin() const
Definition: imgui.h:975
IMGUI_API bool ColorButton(const ImVec4 &col, bool small_height=false, bool outline_border=true)
Definition: imgui.cpp:8944
int ImTextCountUtf8BytesFromStr(const ImWchar *in_text, const ImWchar *in_text_end)
Definition: imgui.cpp:1165
#define STB_TEXTEDIT_K_SHIFT
Definition: imgui.cpp:7543
#define IM_ARRAYSIZE(_ARR)
e
Definition: rmse.py:177
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char *label, const char *label_end=NULL)
Definition: imgui.cpp:5851
void *(* MemAllocFn)(size_t sz)
Definition: imgui.h:828
IMGUI_API void SetStateStorage(ImGuiStorage *tree)
Definition: imgui.cpp:5195
IMGUI_API void AddLine(const ImVec2 &a, const ImVec2 &b, ImU32 col, float thickness=1.0f)
Definition: imgui_draw.cpp:796
IMGUI_API void AddPolyline(const ImVec2 *points, const int num_points, ImU32 col, bool closed, float thickness, bool anti_aliased)
Definition: imgui_draw.cpp:412
IMGUI_API void PushClipRect(ImVec2 clip_rect_min, ImVec2 clip_rect_max, bool intersect_with_current_clip_rect=false)
Definition: imgui_draw.cpp:228
float FrameRounding
Definition: imgui.h:758
IMGUI_API void TextDisabled(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:5253
bool WantCaptureKeyboard
Definition: imgui.h:861
IMGUI_API bool InputText(const char *label, char *buf, size_t buf_size, ImGuiInputTextFlags flags=0, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:8216
bool empty() const
Definition: imgui.h:911
ImVector< ImFont * > Fonts
Definition: imgui.h:1382
IMGUI_API ImVec2 GetItemRectSize()
Definition: imgui.cpp:3267
static void CloseInactivePopups()
Definition: imgui.cpp:3348
IMGUI_API float GetWindowWidth()
Definition: imgui.cpp:4773
IMGUI_API void ** GetVoidPtrRef(ImGuiID key, void *default_val=NULL)
Definition: imgui.cpp:1372
IMGUI_API bool SliderInt(const char *label, int *v, int v_min, int v_max, const char *display_format="%.0f", bool render_bg=false)
Definition: imgui.cpp:6687
IMGUI_API void Build()
Definition: imgui.cpp:1474
static bool BeginPopupEx(const char *str_id, ImGuiWindowFlags extra_flags)
Definition: imgui.cpp:3426
IMGUI_API bool TreeNode(const char *label)
Definition: imgui.cpp:6070
IMGUI_API ImVec2 GetContentRegionMax()
Definition: imgui.cpp:4981
#define STB_TEXTEDIT_K_REDO
Definition: imgui.cpp:7540
GLenum GLuint id
ImVector< ImGuiWindow * > CurrentWindowStack
T * Data
Definition: imgui.h:902
ImVector< Pair > Data
Definition: imgui.h:1033
int KeyMap[ImGuiKey_COUNT]
Definition: imgui.h:794
IMGUI_API bool CheckboxFlags(const char *label, unsigned int *flags, unsigned int flags_value)
Definition: imgui.cpp:7317
iterator begin()
Definition: imgui.h:919
IMGUI_API void TextDisabledV(const char *fmt, va_list args)
Definition: imgui.cpp:5246
ImVector< ImFont * > FontStack
ImVec2 uv
Definition: imgui.h:1190
void(* ImeSetInputScreenPosFn)(int x, int y)
Definition: imgui.h:833
IMGUI_API bool TreeNodeV(const char *str_id, const char *fmt, va_list args)
Definition: imgui.cpp:6024
IMGUI_API bool DragBehavior(const ImRect &frame_bb, ImGuiID id, float *v, float v_speed, float v_min, float v_max, int decimal_precision, float power)
Definition: imgui.cpp:6809
IMGUI_API bool BeginMenuBar()
Definition: imgui.cpp:8796
ImGuiTextFilter(const char *default_filter="")
Definition: imgui.cpp:1430
IMGUI_API void AlignFirstTextHeightToWidgets()
Definition: imgui.cpp:5385
bool empty() const
Definition: imgui.h:977
float ColumnsMinSpacing
Definition: imgui.h:763
float DeltaTime
Definition: imgui.h:787
GLdouble t
#define STB_TEXTEDIT_K_DOWN
Definition: imgui.cpp:7532
bool WantCaptureMouse
Definition: imgui.h:860
GLboolean GLboolean GLboolean GLboolean a
IMGUI_API void PlotHistogram(const char *label, const float *values, int values_count, int values_offset=0, const char *overlay_text=NULL, float scale_min=FLT_MAX, float scale_max=FLT_MAX, ImVec2 graph_size=ImVec2(0, 0), int stride=sizeof(float))
Definition: imgui.cpp:7222
ImGuiSetCond SetNextWindowCollapsedCond
IMGUI_API void MemFree(void *ptr)
Definition: imgui.cpp:1961
IMGUI_API ImGuiContext * CreateContext(void *(*malloc_fn)(size_t)=NULL, void(*free_fn)(void *)=NULL)
Definition: imgui.cpp:1995
IMGUI_API void Clear()
Definition: imgui_draw.cpp:118
unsigned short ImDrawIdx
Definition: imgui.h:1182
#define STB_TEXTEDIT_K_LINEEND
Definition: imgui.cpp:7534
#define STB_TEXTEDIT_GETWIDTH_NEWLINE
GLenum GLuint GLenum GLsizei const GLchar * buf
static bool DataTypeApplyOpFromText(const char *buf, const char *initial_value_buf, ImGuiDataType data_type, void *data_ptr, const char *scalar_format)
Definition: imgui.cpp:6244
IMGUI_API ImVec2 GetMousePos()
Definition: imgui.cpp:3146
GLenum GLsizei len
Definition: glext.h:3285
IMGUI_API void Bullet()
Definition: imgui.cpp:6144
GLuint GLfloat * val
GLuint64 key
Definition: glext.h:8966
static void DataTypeFormatString(ImGuiDataType data_type, void *data_ptr, const char *display_format, char *buf, int buf_size)
Definition: imgui.cpp:6199
ImDrawList * DrawList
static void ClosePopupToLevel(int remaining)
Definition: imgui.cpp:3389
ImGuiDrawContext DC
ImRect Rect() const
ImGuiTextBuffer * LogClipboard
IMGUI_API bool InputFloat3(const char *label, float v[3], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8336
unsigned short ImWchar
Definition: imgui.h:67
GLuint GLuint GLuint GLuint arg1
Definition: glext.h:6215
ImGuiStyleVar Var
IMGUI_API void PushAllowKeyboardFocus(bool v)
Definition: imgui.cpp:4557
IMGUI_API void appendv(const char *fmt, va_list args)
Definition: imgui.cpp:1536
bool PassFilter(const char *text, const char *text_end=NULL) const
Definition: imgui.cpp:1491
IMGUI_API bool IsClippedEx(const ImRect &bb, const ImGuiID *id, bool clip_even_when_logged)
Definition: imgui.cpp:1865
IMGUI_API bool BeginPopup(const char *str_id)
Definition: imgui.cpp:3455
int ImGuiInputTextFlags
Definition: imgui.h:78
ImGuiID ActiveId
ImGuiMouseCursorData MouseCursorData[ImGuiMouseCursor_Count_]
IMGUI_API void SameLine(float pos_x=0.0f, float spacing_w=-1.0f)
Definition: imgui.cpp:9246
ImDrawData RenderDrawData
void pop_back()
Definition: imgui.h:943
IMGUI_API void SetMouseCursor(ImGuiMouseCursor type)
Definition: imgui.cpp:3185
IMGUI_API bool SliderFloat2(const char *label, float v[2], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6735
IMGUI_API ImVec2 GetContentRegionAvail()
Definition: imgui.cpp:4997
GLdouble f
static void AddWindowToRenderList(ImVector< ImDrawList * > &out_render_list, ImGuiWindow *window)
Definition: imgui.cpp:2518
int Size
Definition: imgui.h:900
ImRect MenuBarRect() const
ImGuiSimpleColumns MenuColumns
static void LogRenderedText(const ImVec2 &ref_pos, const char *text, const char *text_end=NULL)
Definition: imgui.cpp:2730
IMGUI_API void CaptureKeyboardFromApp(bool capture=true)
Definition: imgui.cpp:3190
void * ImLoadFileToMemory(const char *filename, const char *file_open_mode, int *out_file_size, int padding_bytes)
Definition: imgui.cpp:1248
GLenum mode
bool SetNextTreeNodeOpenVal
float CurrentLineTextBaseOffset
IMGUI_API void SetFloat(ImGuiID key, float val)
Definition: imgui.cpp:1397
ImGuiInputTextFlags EventFlag
Definition: imgui.h:1065
float DragSpeedDefaultRatio
ImGuiID PopupID
ImVec2 DisplayOffset
Definition: imgui.h:1405
IMGUI_API float GetScrollMaxY()
Definition: imgui.cpp:5149
IMGUI_API void SetCurrentContext(ImGuiContext *ctx)
Definition: imgui.cpp:1990
GLuint GLenum * rate
Definition: glext.h:10991
const GLfloat * tc
Definition: glext.h:12710
ImFontAtlas * ContainerAtlas
Definition: imgui.h:1416
GLfloat GLfloat GLfloat alpha
IMGUI_API ImDrawList * GetWindowDrawList()
Definition: imgui.cpp:5045
IMGUI_API bool ItemAdd(const ImRect &bb, const ImGuiID *id)
Definition: imgui.cpp:1840
ImVector< ImGuiWindow * > Windows
IMGUI_API bool Begin(const char *name, bool *p_open=NULL, ImGuiWindowFlags flags=0)
Definition: imgui.cpp:3772
#define IM_ASSERT(_EXPR)
Definition: imgui.h:29
IMGUI_API bool InputInt2(const char *label, int v[2], ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8374
int ImGuiWindowFlags
Definition: imgui.h:76
IMGUI_API void PopStyleVar(int count=1)
Definition: imgui.cpp:4675
IMGUI_API void SetScrollY(float scroll_y)
Definition: imgui.cpp:5162
float FontSize
Definition: imgui.h:1403
ImVec2 SizeContentsExplicit
GLsizeiptr size
float Alpha
Definition: imgui.h:751
ImGuiID GetID(const char *str, const char *str_end=NULL)
Definition: imgui.cpp:1751
IMGUI_API ImVec2 CalcTextSize(const char *text, const char *text_end=NULL, bool hide_text_after_double_hash=false, float wrap_width=-1.0f)
Definition: test-wrap.cpp:15
IMGUI_API bool CollapsingHeader(const char *label, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:5961
static void CheckStacksSize(ImGuiWindow *window, bool write)
Definition: imgui.cpp:3619
ImGuiStb::STB_TexteditState StbState
IMGUI_API ImVec2 GetWindowContentRegionMin()
Definition: imgui.cpp:5009
IMGUI_API void AddDrawCmd()
Definition: imgui_draw.cpp:160
IMGUI_API bool IsPosHoveringAnyWindow(const ImVec2 &pos)
Definition: imgui.cpp:3044
IMGUI_API bool ListBoxHeader(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:8642
IMGUI_API void Dummy(const ImVec2 &size)
Definition: imgui.cpp:9171
IMGUI_API void SetNextWindowPosCenter(ImGuiSetCond cond=0)
Definition: imgui.cpp:4930
IMGUI_API void KeepAliveID(ImGuiID id)
Definition: imgui.cpp:1802
static bool ImCharIsSpace(int c)
const char * str_end(const char *s, const char *)
void Expand(const float amount)
IMGUI_API bool IsAnyItemHovered()
Definition: imgui.cpp:3228
static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING *obj, int pos, const ImWchar *new_text, int new_text_len)
Definition: imgui.cpp:7506
ImVector< char > TempTextBuffer
int ImTextStrFromUtf8(ImWchar *buf, int buf_size, const char *in_text, const char *in_text_end, const char **in_text_remaining)
Definition: imgui.cpp:1068
const char * ImStristr(const char *haystack, const char *haystack_end, const char *needle, const char *needle_end)
Definition: imgui.cpp:919
char front() const
Definition: imgui.h:978
float w
Definition: imgui.h:100
const GLubyte * c
Definition: glext.h:12690
ImFont InputTextPasswordFont
IMGUI_API bool IsMouseDragging(int button=0, float lock_threshold=-1.0f)
Definition: imgui.cpp:3135
int DisplayStart
Definition: imgui.h:1138
static float ImLengthSqr(const ImVec2 &lhs)
GLdouble GLdouble r
IMGUI_API ImVec2 GetWindowContentRegionMax()
Definition: imgui.cpp:5015
IMGUI_API bool IsRectVisible(const ImVec2 &size)
Definition: imgui.cpp:9182
IMGUI_API bool SliderIntN(const char *label, int *v, int components, int v_min, int v_max, const char *display_format)
Definition: imgui.cpp:6750
IMGUI_API bool Step()
Definition: imgui.cpp:1654
static float STB_TEXTEDIT_GETWIDTH(STB_TEXTEDIT_STRING *obj, int line_start_idx, int char_idx)
Definition: imgui.cpp:7463
ImVec2 WindowMinSize
Definition: imgui.h:753
GLenum GLint GLint * precision
Definition: glext.h:1883
static ImGuiIniData * FindWindowSettings(const char *name)
Definition: imgui.cpp:2337
ImGuiTextEditState InputTextState
IMGUI_API void TextUnformatted(const char *text, const char *text_end=NULL)
Definition: imgui.cpp:5276
IMGUI_API void TreePushRawID(ImGuiID id)
Definition: imgui.cpp:9522
IMGUI_API bool DragFloat4(const char *label, float v[4], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6984
ImGuiWindow * RootWindow
static void SetWindowCollapsed(ImGuiWindow *window, bool collapsed, ImGuiSetCond cond)
Definition: imgui.cpp:4876
ImU32 ImHash(const void *data, int data_size, ImU32 seed)
Definition: imgui.cpp:960
float MouseDownDuration[5]
Definition: imgui.h:881
static bool Items_ArrayGetter(void *data, int idx, const char **out_text)
Definition: imgui.cpp:8389
ImVector< ImGuiColMod > ColorModifiers
GLdouble x
ImGuiWindow * MovedWindow
IMGUI_API bool ColorEdit3(const char *label, float col[3])
Definition: imgui.cpp:8969
IMGUI_API void SetColumnOffset(int column_index, float offset_x)
Definition: imgui.cpp:9363
IMGUI_API void SetNextWindowContentWidth(float width)
Definition: imgui.cpp:4960
ImVec2 Max
IMGUI_API void Unindent(float indent_w=0.0f)
Definition: imgui.cpp:9498
const char * _OwnerName
Definition: imgui.h:1222
static ImGuiIniData * AddWindowSettings(const char *name)
Definition: imgui.cpp:2350
IMGUI_API int GetColumnsCount()
Definition: imgui.cpp:9322
static ImRect GetVisibleRect()
Definition: imgui.cpp:3296
IMGUI_API bool InputIntN(const char *label, int *v, int components, ImGuiInputTextFlags extra_flags)
Definition: imgui.cpp:8346
#define IM_COL32(R, G, B, A)
Definition: imgui.h:1157
const float * Values
Definition: imgui.cpp:7198
IMGUI_API bool SliderAngle(const char *label, float *v_rad, float v_degrees_min=-360.0f, float v_degrees_max=+360.0f)
Definition: imgui.cpp:6679
float ItemWidthDefault
IMGUI_API void FocusWindow(ImGuiWindow *window)
Definition: imgui.cpp:4454
ImVector< ImDrawCmd > CmdBuffer
Definition: imgui.h:1217
GLdouble GLdouble x2
ImGuiWindow * ActiveIdWindow
bool AutoFitOnlyGrows
void(* SetClipboardTextFn)(const char *text)
Definition: imgui.h:824
ImVector< ImGuiStyleMod > StyleModifiers
IMGUI_API void LabelText(const char *label, const char *fmt,...) IM_PRINTFARGS(2)
Definition: imgui.cpp:5423
IMGUI_API void AddText(const ImVec2 &pos, ImU32 col, const char *text_begin, const char *text_end=NULL)
Definition: imgui_draw.cpp:951
bool Contains(const ImVec2 &p) const
ImGuiID MoveID
ImRect ContentsRegionRect
int ImGuiStyleVar
Definition: imgui.h:71
ImGuiID HoveredIdPreviousFrame
IMGUI_API bool SliderFloat3(const char *label, float v[3], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6740
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup()
Definition: imgui.cpp:3152
float MouseDoubleClickTime
Definition: imgui.h:791
static bool IsKeyPressedMap(ImGuiKey key, bool repeat=true)
Definition: imgui.cpp:3049
void(* ImGuiSizeConstraintCallback)(ImGuiSizeConstraintCallbackData *data)
Definition: imgui.h:82
float GrabMinSize
Definition: imgui.h:766
float KeysDownDurationPrev[512]
Definition: imgui.h:885
IMGUI_API ImGuiIO & GetIO()
Definition: imgui.cpp:2014
GLint GLsizei GLsizei height
IMGUI_API bool InputScalarAsWidgetReplacement(const ImRect &aabb, const char *label, ImGuiDataType data_type, void *data_ptr, ImGuiID id, int decimal_precision)
Definition: imgui.cpp:6307
IMGUI_API bool SeekSlider(const char *label, int *v, const char *display_format="%.0f%%")
Definition: imgui.cpp:6559
int MetricsRenderIndices
Definition: imgui.h:866
IMGUI_API void SetNextWindowSize(const ImVec2 &size, ImGuiSetCond cond=0)
Definition: imgui.cpp:4937
int ImGuiKey
Definition: imgui.h:72
float GetWidth() const
ImVec2 OsImePosSet
IMGUI_API bool DragInt4(const char *label, int v[4], float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: imgui.cpp:7062
IMGUI_API bool InputFloat2(const char *label, float v[2], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8331
IMGUI_API bool ListBox(const char *label, int *current_item, const char **items, int items_count, int height_in_items=-1)
Definition: imgui.cpp:8699
IMGUI_API bool IsRootWindowOrAnyChildFocused()
Definition: imgui.cpp:4761
float z
Definition: imgui.h:100
IMGUI_API bool InputFloat4(const char *label, float v[4], int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8341
ImVec2 WindowPadding
static void STB_TEXTEDIT_DELETECHARS(STB_TEXTEDIT_STRING *obj, int pos, int n)
Definition: imgui.cpp:7491
IMGUI_API ImFont * GetFont()
Definition: imgui.cpp:5051
IMGUI_API void EndGroup()
Definition: imgui.cpp:9209
static int ImTextCharToUtf8(char *buf, int buf_size, unsigned int c)
Definition: imgui.cpp:1103
IMGUI_API float GetTime()
Definition: imgui.cpp:2030
IMGUI_API void TextV(const char *fmt, va_list args)
Definition: imgui.cpp:5207
bool KeysDown[512]
Definition: imgui.h:848
IMGUI_API int GetColumnIndex()
Definition: imgui.cpp:9316
IMGUI_API void ChannelsMerge()
Definition: imgui_draw.cpp:305
IMGUI_API void Spacing()
Definition: imgui.cpp:9163
IMGUI_API void LogToFile(int max_depth=-1, const char *filename=NULL)
Definition: imgui.cpp:5714
ImGuiID ActiveIdPreviousFrame
IMGUI_API void SetNextWindowSizeConstraints(const ImVec2 &size_min, const ImVec2 &size_max, ImGuiSizeConstraintCallback custom_callback=NULL, void *custom_callback_data=NULL)
Definition: imgui.cpp:4944
GLbitfield flags
IMGUI_API bool InputFloat(const char *label, float *v, float step=0.0f, float step_fast=0.0f, int decimal_precision=-1, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8286
IMGUI_API ImGuiContext * GetCurrentContext()
Definition: imgui.cpp:1985
def callback(frame)
Definition: t265_stereo.py:91
static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(STB_TEXTEDIT_STRING *obj, int idx)
Definition: imgui.cpp:7486
void reserve(int new_capacity)
Definition: imgui.h:932
IMGUI_API void SetWindowFocus()
Definition: imgui.cpp:4904
ImVector< bool > ButtonRepeatStack
float ScrollbarRounding
Definition: imgui.h:765
float GetHeight() const
IMGUI_API bool IsWindowCollapsed()
Definition: imgui.cpp:4892
IMGUI_API void SetCursorPosX(float x)
Definition: imgui.cpp:5101
GLenum GLenum GLsizei const GLuint GLboolean enabled
IMGUI_API float GetContentRegionAvailWidth()
Definition: imgui.cpp:5003
GLint GLint GLsizei GLint border
IMGUI_API int GetInt(ImGuiID key, int default_val=0) const
Definition: imgui.cpp:1321
#define IMGUI_VERSION
Definition: imgui.h:19
bool KeyShift
Definition: imgui.h:845
string cr
Definition: log.py:31
GLuint start
IMGUI_API void ColorEditMode(ImGuiColorEditMode mode)
Definition: imgui.cpp:9120
int ImTextCountCharsFromUtf8(const char *in_text, const char *in_text_end)
Definition: imgui.cpp:1087
static int STB_TEXTEDIT_KEYTOTEXT(int key)
Definition: imgui.cpp:7464
float CalcFontSize() const
GLint j
ImVector< float > IndexXAdvance
Definition: imgui.h:1407
GLdouble GLdouble GLint stride
IMGUI_API void PushItemWidth(float item_width)
Definition: imgui.cpp:4486
static ImGuiContext GImDefaultContext
Definition: imgui.cpp:714
IMGUI_API void Text(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:5223
IMGUI_API bool Button(const char *label, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:5573
ImVec2 ScrollTargetCenterRatio
IMGUI_API void Value(const char *prefix, bool b)
Definition: imgui.cpp:9538
ImU32 col
Definition: imgui.h:1191
IMGUI_API float GetItemsLineHeightWithSpacing()
Definition: imgui.cpp:5039
ImGuiWindow * HoveredRootWindow
static bool IsPopupOpen(ImGuiID id)
Definition: imgui.cpp:3316
int FocusIdxTabRequestCurrent
GLint first
IMGUI_API ImGuiWindow * GetParentWindow()
Definition: imgui.cpp:1779
IMGUI_API void Separator()
Definition: imgui.cpp:9127
IMGUI_API void End()
Definition: imgui.cpp:4330
#define STB_TEXTEDIT_K_DELETE
Definition: imgui.cpp:7537
ImVector< bool > AllowKeyboardFocusStack
void clear()
Definition: imgui.h:918
static int ImTextCountUtf8BytesFromChar(unsigned int c)
Definition: imgui.cpp:1140
IMGUI_API void FocusableItemUnregister(ImGuiWindow *window)
Definition: imgui.cpp:1919
IMGUI_API void ItemSize(const ImVec2 &size, float text_offset_y=0.0f)
Definition: imgui.cpp:1810
Definition: imgui.h:98
IMGUI_API void BeginGroup()
Definition: imgui.cpp:9189
bool FontAllowUserScaling
Definition: imgui.h:801
IMGUI_API bool DragFloatRange2(const char *label, float *v_current_min, float *v_current_max, float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", const char *display_format_max=NULL, float power=1.0f)
Definition: imgui.cpp:6989
IMGUI_API bool SliderFloat4(const char *label, float v[4], float v_min, float v_max, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6745
IMGUI_API void AddCircleFilled(const ImVec2 &centre, float radius, ImU32 col, int num_segments=12)
Definition: imgui_draw.cpp:901
const ImWchar * ImStrbolW(const ImWchar *buf_mid_line, const ImWchar *buf_begin)
Definition: imgui.cpp:912
ImVector< ImGuiColumnData > ColumnsData
float DragSpeedScaleSlow
IMGUI_API float GetScrollX()
Definition: imgui.cpp:5133
IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2 &a, const ImVec2 &b, const ImVec2 &uv0=ImVec2(0, 0), const ImVec2 &uv1=ImVec2(1, 1), ImU32 col=0xFFFFFFFF)
Definition: imgui_draw.cpp:956
IMGUI_API void Begin(int items_count, float items_height=-1.0f)
Definition: imgui.cpp:1627
int ImGuiSliderFlags
IMGUI_API bool IsKeyReleased(int key_index)
Definition: imgui.cpp:3086
ImVec2 GetTL() const
float GetCharAdvance(ImWchar c) const
Definition: imgui.h:1426
ImGuiID ScalarAsInputTextId
bool MouseDown[5]
Definition: imgui.h:841
IMGUI_API bool SliderInt4(const char *label, int v[4], int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6787
IMGUI_API bool DragFloat(const char *label, float *v, float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6884
#define va_copy(dest, src)
Definition: imgui.cpp:1532
IMGUI_API bool BeginPopupContextVoid(const char *str_id=NULL, int mouse_button=1)
Definition: imgui.cpp:3523
static int is_word_boundary_from_right(STB_TEXTEDIT_STRING *obj, int idx)
Definition: imgui.cpp:7480
unsigned int _VtxCurrentIdx
Definition: imgui.h:1223
static int InputTextCalcTextLenAndLineCount(const char *text_begin, const char **out_text_end)
Definition: imgui.cpp:7399
int ImGuiMouseCursor
Definition: imgui.h:75
bool ImIsPointInTriangle(const ImVec2 &p, const ImVec2 &a, const ImVec2 &b, const ImVec2 &c)
Definition: imgui.cpp:876
IMGUI_API bool IsHovered(const ImRect &bb, ImGuiID id, bool flatten_childs=false)
Definition: imgui.cpp:1878
IMGUI_API float GetColumnWidth(int column_index=-1)
Definition: imgui.cpp:9377
IMGUI_API ImVec2 GetWindowSize()
Definition: imgui.cpp:4828
float FallbackXAdvance
Definition: imgui.h:1410
GLenum GLenum GLuint components
Definition: glext.h:8863
float PrevLineTextBaseOffset
void Update(int count, float spacing, bool clear)
Definition: imgui.cpp:1577
IMGUI_API void EndPopup()
Definition: imgui.cpp:3489
IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col)
Definition: imgui.cpp:2913
IMGUI_API float GetTreeNodeToLabelSpacing()
Definition: imgui.cpp:6085
bool KeyCtrl
Definition: imgui.h:844
IMGUI_API ImVec2 GetFontTexUvWhitePixel()
Definition: imgui.cpp:5061
bool AntiAliasedShapes
Definition: imgui.h:771
#define STB_TEXTEDIT_K_BACKSPACE
Definition: imgui.cpp:7538
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char *text, const char *text_end, float wrap_width)
Definition: imgui.cpp:2808
IMGUI_API void RenderBullet(ImVec2 pos)
Definition: imgui.cpp:2907
IMGUI_API void NextColumn()
Definition: imgui.cpp:9280
float x
Definition: imgui.h:100
ImVector< ImGuiPopupRef > OpenPopupStack
bool MouseDownOwned[5]
Definition: imgui.h:880
float DeclColumns(float w0, float w1, float w2)
Definition: imgui.cpp:1594
IMGUI_API void RenderCollapseTriangle(ImVec2 pos, bool is_open, float scale=1.0f, bool shadow=false)
Definition: imgui.cpp:2878
float IndentSpacing
Definition: imgui.h:762
IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4 &col)
Definition: imgui.cpp:4599
IMGUI_API float GetWindowHeight()
Definition: imgui.cpp:4779
static ImVec2 FindBestPopupWindowPos(const ImVec2 &base_pos, const ImVec2 &size, int *last_dir, const ImRect &rect_to_avoid)
Definition: imgui.cpp:3633
static void MarkSettingsDirty()
Definition: imgui.cpp:2452
IMGUI_API bool ButtonEx(const char *label, const ImVec2 &size_arg=ImVec2(0, 0), ImGuiButtonFlags flags=0)
Definition: imgui.cpp:5523
#define STB_TEXTEDIT_K_WORDLEFT
Definition: imgui.cpp:7541
IMGUI_API bool DragFloat2(const char *label, float v[2], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6974
ImGuiPlotArrayGetterData(const float *values, int stride)
Definition: imgui.cpp:7201
IMGUI_API bool BeginMainMenuBar()
Definition: imgui.cpp:8771
IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiSetCond cond=0)
Definition: imgui.cpp:6091
IMGUI_API ImU32 ColorConvertFloat4ToU32(const ImVec4 &in)
Definition: imgui.cpp:1185
ImVec2 DisplaySafeAreaPadding
Definition: imgui.h:769
IMGUI_API bool SliderFloatN(const char *label, float *v, int components, float v_min, float v_max, const char *display_format, float power)
Definition: imgui.cpp:6708
const Glyph * FallbackGlyph
Definition: imgui.h:1409
IMGUI_API bool Combo(const char *label, int *current_item, const char **items, int items_count, int height_in_items=-1, bool show_arrow_down=true)
Definition: imgui.cpp:8418
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
Definition: imgui.cpp:677
const char *(* GetClipboardTextFn)()
Definition: imgui.h:823
IMGUI_API void PushFont(ImFont *font)
Definition: imgui.cpp:4539
float SettingsDirtyTimer
ImGuiWindow * CurrentWindow
ImVec2 DisplayWindowPadding
Definition: imgui.h:768
IMGUI_API void SetClipboardText(const char *text)
Definition: imgui.cpp:1972
float IniSavingRate
Definition: imgui.h:788
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble GLdouble w2
Definition: glext.h:12384
IMGUI_API bool InvisibleButton(const char *str_id, const ImVec2 &size)
Definition: imgui.cpp:5591
float y
Definition: imgui.h:90
ImGuiWindow(const char *name)
Definition: imgui.cpp:1694
IMGUI_API void SetBool(ImGuiID key, bool val)
Definition: imgui.cpp:1392
ImGuiStyle Style
int MetricsRenderVertices
Definition: imgui.h:865
IMGUI_API void EndChild()
Definition: imgui.cpp:3573
IMGUI_API float GetWindowContentRegionWidth()
Definition: imgui.cpp:5021
IMGUI_API float GetScrollMaxX()
Definition: imgui.cpp:5143
ImGuiSizeConstraintCallback SetNextWindowSizeConstraintCallback
ImVec2 FramePadding
Definition: imgui.h:757
IMGUI_API void SetTooltipV(const char *fmt, va_list args)
Definition: imgui.cpp:3282
static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(STB_TEXTEDIT_STRING *obj, int idx)
Definition: imgui.cpp:7481
IMGUI_API bool BeginMenu(const char *label, bool enabled=true)
Definition: imgui.cpp:8833
IMGUI_API float GetTextLineHeightWithSpacing()
Definition: imgui.cpp:5033
GLsizei const GLfloat * values
iterator insert(const_iterator it, const value_type &v)
Definition: imgui.h:946
GLdouble GLdouble GLint GLint GLdouble v1
int LogAutoExpandMaxDepth
IMGUI_API bool SliderBehavior(const ImRect &frame_bb, ImGuiID id, float *v, float v_min, float v_max, float power, int decimal_precision, ImGuiSliderFlags flags=0, bool render_bg=false)
Definition: imgui.cpp:6375
bool SetNextWindowSizeConstraint
IMGUI_API void ListBoxFooter()
Definition: imgui.cpp:8683
float FramerateSecPerFrame[120]
ImVec4 Colors[ImGuiCol_COUNT]
Definition: imgui.h:773
IMGUI_API bool SliderIntWithSteps(const char *label, int *v, int v_min, int v_max, int v_step=1, const char *display_format="%.3f")
Definition: imgui.cpp:6793
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border=true, float rounding=0.0f)
Definition: imgui.cpp:2865
ImGuiWindowFlags Flags
IMGUI_API void append(const char *fmt,...) IM_PRINTFARGS(2)
Definition: imgui.cpp:1557
ImVec2 GetTR() const
Definition: example.hpp:70
IMGUI_API float CalcItemWidth()
Definition: imgui.cpp:4514
static int ImMin(int lhs, int rhs)
IMGUI_API void SetInt(ImGuiID key, int val)
Definition: imgui.cpp:1381
static float Plot_ArrayGetter(void *data, int idx)
Definition: imgui.cpp:7204
ImDrawCallback UserCallback
Definition: imgui.h:1174
int TotalIdxCount
Definition: imgui.h:1303
GLuint GLfloat GLfloat GLfloat x1
Definition: glext.h:9721
IMGUI_API bool SliderFloat(const char *label, float *v, float v_min, float v_max, const char *display_format="%.3f", float power=1.0f, bool render_bg=false)
Definition: imgui.cpp:6570
int SetWindowSizeAllowFlags
IMGUI_API void DestroyContext(ImGuiContext *ctx)
Definition: imgui.cpp:2005
static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow *r, STB_TEXTEDIT_STRING *obj, int line_start_idx)
Definition: imgui.cpp:7466
IMGUI_API void LogToTTY(int max_depth=-1)
Definition: imgui.cpp:5699
static void ClosePopup(ImGuiID id)
Definition: imgui.cpp:3399
float MouseDoubleClickMaxDist
Definition: imgui.h:792
float GrabRounding
Definition: imgui.h:767
ImDrawVert * _VtxWritePtr
Definition: imgui.h:1224
float FontGlobalScale
Definition: imgui.h:800
IMGUI_API ImVec2 GetCursorScreenPos()
Definition: imgui.cpp:5121
IMGUI_API ImGuiWindow * FindWindowByName(const char *name)
Definition: imgui.cpp:3661
IMGUI_API bool DragIntN(const char *label, int *v, int components, float v_speed, int v_min, int v_max, const char *display_format)
Definition: imgui.cpp:7025
int ImFormatStringV(char *buf, int buf_size, const char *fmt, va_list args)
Definition: imgui.cpp:951
bool KeySuper
Definition: imgui.h:847
IMGUI_API void Shutdown()
Definition: imgui.cpp:2277
#define STB_TEXTEDIT_K_WORDRIGHT
Definition: imgui.cpp:7542
void(* RenderDrawListsFn)(ImDrawData *data)
Definition: imgui.h:819
IMGUI_API void EndChildFrame()
Definition: imgui.cpp:3611
int FocusIdxAllCounter
IMGUI_API bool SliderInt3(const char *label, int v[3], int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6782
IMGUI_API ImGuiStyle()
Definition: imgui.cpp:725
GLdouble GLdouble GLdouble q
void push_back(const value_type &v)
Definition: imgui.h:942
#define IM_PI
ImVector< ImGuiWindow * > WindowsSortBuffer
IMGUI_API void PopItemWidth()
Definition: imgui.cpp:4507
ImVec2 GetBL() const
int mx
Definition: rmse.py:54
float XAdvance
Definition: imgui.h:1397
float KeyRepeatDelay
Definition: imgui.h:795
#define STB_TEXTEDIT_K_RIGHT
Definition: imgui.cpp:7530
IMGUI_API void TreePop()
Definition: imgui.cpp:9530
iterator erase(const_iterator it)
Definition: imgui.h:945
float MouseDragThreshold
Definition: imgui.h:793
int TotalVtxCount
Definition: imgui.h:1302
IMGUI_API bool DragFloatN(const char *label, float *v, int components, float v_speed, float v_min, float v_max, const char *display_format, float power)
Definition: imgui.cpp:6947
value_type * iterator
Definition: imgui.h:905
#define IM_NEWLINE
Definition: imgui.cpp:873
ImVec2 MousePosPrev
Definition: imgui.h:873
static auto it
ImVec2 TexUvWhitePixel
Definition: imgui.h:1381
int FocusIdxAllRequestNext
bool AntiAliasedLines
Definition: imgui.h:770
IMGUI_API bool InputScalarEx(const char *label, ImGuiDataType data_type, void *data_ptr, void *step_ptr, void *step_fast_ptr, const char *scalar_format, ImGuiInputTextFlags extra_flags)
Definition: imgui.cpp:8230
static void SetCurrentWindow(ImGuiWindow *window)
Definition: imgui.cpp:1771
ImVec2 ScrollbarSizes
IMGUI_API bool IsItemVisible()
Definition: imgui.cpp:3238
GLuint in
Definition: glext.h:8859
static void SaveSettings()
Definition: imgui.cpp:2410
IMGUI_API int * GetIntRef(ImGuiID key, int default_val=0)
Definition: imgui.cpp:1351
static float ImSaturate(float f)
IMGUI_API bool ButtonBehavior(const ImRect &bb, ImGuiID id, bool *out_hovered, bool *out_held, ImGuiButtonFlags flags=0)
Definition: imgui.cpp:5443
#define STB_TEXTEDIT_STRING
ImGuiSetCond SetNextWindowSizeCond
ImVector< float > TextWrapPosStack
Definition: imgui.h:1392
IMGUI_API void TextColoredV(const ImVec4 &col, const char *fmt, va_list args)
Definition: imgui.cpp:5231
ImWchar InputCharacters[16+1]
Definition: imgui.h:849
IMGUI_API void EndFrame()
Definition: imgui.cpp:2548
GLuint GLsizei const GLchar * label
IMGUI_API float GetTextLineHeight()
Definition: imgui.cpp:5027
IMGUI_API bool SliderInt2(const char *label, int v[2], int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6777
float DragSpeedScaleFast
int SetWindowPosAllowFlags
IMGUI_API bool IsMouseHoveringWindow()
Definition: imgui.cpp:3032
IMGUI_API void PlotEx(ImGuiPlotType plot_type, const char *label, float(*values_getter)(void *data, int idx), void *data, int values_count, int values_offset, const char *overlay_text, float scale_min, float scale_max, ImVec2 graph_size)
Definition: imgui.cpp:7092
int ImFormatString(char *buf, int buf_size, const char *fmt,...)
Definition: imgui.cpp:941
static void AddWindowToSortedBuffer(ImVector< ImGuiWindow * > &out_sorted_windows, ImGuiWindow *window)
Definition: imgui.cpp:2473
static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
Definition: imgui.cpp:9695
static void SetClipboardTextFn_DefaultImpl(const char *text)
Definition: imgui.cpp:9655
signed __int64 int64_t
Definition: stdint.h:89
static ImGuiWindow * GetFrontMostModalRootWindow()
Definition: imgui.cpp:3379
IMGUI_API void TreePush(const char *str_id=NULL)
Definition: imgui.cpp:9506
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow *window)
Definition: imgui.cpp:1786
IMGUI_API bool MenuItem(const char *label, const char *shortcut=NULL, bool selected=false, bool enabled=true)
Definition: imgui.cpp:8733
IMGUI_API bool CloseButton(ImGuiID id, const ImVec2 &pos, float radius)
Definition: imgui.cpp:5611
GLint GLsizei count
IMGUI_API bool GetBool(ImGuiID key, bool default_val=false) const
Definition: imgui.cpp:1329
void PathLineTo(const ImVec2 &pos)
Definition: imgui.h:1261
IMGUI_API int GetFrameCount()
Definition: imgui.cpp:2035
int ImGuiButtonFlags
Definition: imgui.h:107
IMGUI_API void End()
Definition: imgui.cpp:1643
#define STB_TEXTEDIT_K_UP
Definition: imgui.cpp:7531
bool HoveredIdAllowOverlap
void * ImeWindowHandle
Definition: imgui.h:834
IMGUI_API bool BeginPopupModal(const char *name, bool *p_open=NULL, ImGuiWindowFlags extra_flags=0)
Definition: imgui.cpp:3465
IMGUI_API const char * GetClipboardText()
Definition: imgui.cpp:1967
ImVector< short > IndexLookup
Definition: imgui.h:1408
IMGUI_API bool Selectable(const char *label, bool selected=false, ImGuiSelectableFlags flags=0, const ImVec2 &size=ImVec2(0, 0))
Definition: imgui.cpp:8550
IMGUI_API void SetNextWindowContentSize(const ImVec2 &size)
Definition: imgui.cpp:4953
static void PushColumnClipRect(int column_index=-1)
Definition: imgui.cpp:9387
IMGUI_API ImGuiIO()
Definition: imgui.cpp:795
ImVec2 GetClosestPoint(ImVec2 p, bool on_edge) const
Definition: imgui.h:780
IMGUI_API void PopButtonRepeat()
Definition: imgui.cpp:4578
IMGUI_API bool ColorEdit4(const char *label, float col[4], bool show_alpha=true)
Definition: imgui.cpp:8985
bool WantTextInput
Definition: imgui.h:862
IMGUI_API bool Checkbox(const char *label, bool *v)
Definition: imgui.cpp:7269
IMGUI_API float GetFloat(ImGuiID key, float default_val=0.0f) const
Definition: imgui.cpp:1334
ImU32 ImGuiID
Definition: imgui.h:69
ImVector< ImDrawVert > VtxBuffer
Definition: imgui.h:1219
IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags=0)
Definition: imgui.cpp:5804
float Ascent
Definition: imgui.h:1417
IMGUI_API bool VSliderInt(const char *label, const ImVec2 &size, int *v, int v_min, int v_max, const char *display_format="%.0f")
Definition: imgui.cpp:6697
IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul=1.0f)
IMGUI_API float CalcWrapWidthForPos(const ImVec2 &pos, float wrap_pos_x)
Definition: imgui.cpp:1938
int ImGuiAlign
Definition: imgui.h:73
float rs2_vector::* pos
ImVec2 MouseDelta
Definition: imgui.h:874
IMGUI_API ImVec2 GetItemRectMax()
Definition: imgui.cpp:3261
unsigned int ElemCount
Definition: imgui.h:1171
float MouseDragMaxDistanceSqr[5]
Definition: imgui.h:883
IMGUI_API void * GetVoidPtr(ImGuiID key) const
Definition: imgui.cpp:1342
IMGUI_API float GetScrollY()
Definition: imgui.cpp:5138
int SetWindowCollapsedAllowFlags
IMGUI_API void SetCursorScreenPos(const ImVec2 &pos)
Definition: imgui.cpp:5127
IMGUI_API bool InputFloatN(const char *label, float *v, int components, int decimal_precision, ImGuiInputTextFlags extra_flags)
Definition: imgui.cpp:8303
int MetricsActiveWindows
Definition: imgui.h:867
int ImGuiSelectableFlags
Definition: imgui.h:79
IMGUI_API void LogToClipboard(int max_depth=-1)
Definition: imgui.cpp:5741
int ImGuiSetCond
Definition: imgui.h:77
float MenuBarHeight() const
#define STB_TEXTEDIT_K_TEXTSTART
Definition: imgui.cpp:7535
const char * begin() const
Definition: imgui.h:1004
bool SetWindowPosCenterWanted
IMGUI_API void EndMenuBar()
Definition: imgui.cpp:8816
void clear()
Definition: imgui.h:1008
IMGUI_API const char * GetVersion()
Definition: imgui.cpp:1978
float MouseWheel
Definition: imgui.h:842
IMGUI_API void SetContentRegionWidth(float y)
Definition: imgui.cpp:4990
int ImStrnicmp(const char *str1, const char *str2, int count)
Definition: imgui.cpp:891
ImVector< ImGuiGroupData > GroupStack
IMGUI_API void PushID(const char *str_id)
Definition: imgui.cpp:6098
#define NULL
Definition: tinycthread.c:47
IMGUI_API void Clear()
IMGUI_API bool DragIntRange2(const char *label, int *v_current_min, int *v_current_max, float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f", const char *display_format_max=NULL)
Definition: imgui.cpp:7067
IMGUI_API ImGuiID GetID(const char *str_id)
Definition: imgui.cpp:6129
bool KeyAlt
Definition: imgui.h:846
IMGUI_API bool InputTextEx(const char *label, char *buf, int buf_size, const ImVec2 &size_arg, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback=NULL, void *user_data=NULL)
Definition: imgui.cpp:7653
ImVec4 PreviousValue
int i
ImVector< ImGuiID > IDStack
ImGuiMouseCursor MouseCursor
float KeyRepeatRate
Definition: imgui.h:796
ImVec2 pos
Definition: imgui.h:1189
ImVec2 TouchExtraPadding
Definition: imgui.h:761
ImGuiWindow * GetCurrentWindow()
IMGUI_API void SetAllInt(int val)
Definition: imgui.cpp:1419
IMGUI_API ImVec2 GetWindowPos()
Definition: imgui.cpp:4785
void Floor()
IMGUI_API bool DragInt2(const char *label, int v[2], float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: imgui.cpp:7052
IMGUI_API ImGuiStyle & GetStyle()
Definition: imgui.cpp:2019
IMGUI_API void TextWrappedV(const char *fmt, va_list args)
Definition: imgui.cpp:5261
IMGUI_API void ColorConvertRGBtoHSV(float r, float g, float b, float &out_h, float &out_s, float &out_v)
Definition: imgui.cpp:1197
int ImGuiCol
Definition: imgui.h:70
IMGUI_API void SetItemAllowOverlap()
Definition: imgui.cpp:3246
IMGUI_API void CloseCurrentPopup()
Definition: imgui.cpp:3408
IMGUI_API void PushClipRectFullScreen()
Definition: imgui_draw.cpp:246
IMGUI_API bool IsKeyDown(int key_index)
Definition: imgui.cpp:3061
static int ImClamp(int v, int mn, int mx)
IMGUI_API void PopClipRect()
Definition: imgui.cpp:2540
const char * IniFilename
Definition: imgui.h:789
ImVector< Glyph > Glyphs
Definition: imgui.h:1406
float MouseDownDurationPrev[5]
Definition: imgui.h:882
IMGUI_API void OpenPopup(const char *str_id)
Definition: imgui.cpp:3343
IMGUI_API ImVec2 CalcTextSizeA(float size, float max_width, float wrap_width, const char *text_begin, const char *text_end=NULL, const char **remaining=NULL) const
void * SetNextWindowSizeConstraintCallbackUserData
IMGUI_API bool DragInt3(const char *label, int v[3], float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: imgui.cpp:7057
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_x, float default_y)
Definition: imgui.cpp:1925
ImGuiDataType
IMGUI_API void AddRect(const ImVec2 &a, const ImVec2 &b, ImU32 col, float rounding=0.0f, int rounding_corners=0x0F, float thickness=1.0f)
Definition: imgui_draw.cpp:806
bool WordMovementUsesAltKey
Definition: imgui.h:807
GLuint * ids
IMGUI_API bool DragFloat3(const char *label, float v[3], float v_speed=1.0f, float v_min=0.0f, float v_max=0.0f, const char *display_format="%.3f", float power=1.0f)
Definition: imgui.cpp:6979
ImVector< char > InitialText
IMGUI_API void TextWrapped(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:5268
iterator end()
Definition: imgui.h:921
IMGUI_API void SetCursorPosY(float y)
Definition: imgui.cpp:5108
static void AddDrawListToRenderList(ImVector< ImDrawList * > &out_render_list, ImDrawList *draw_list)
Definition: imgui.cpp:2490
ImVec2 DragLastMouseDelta
ImGuiWindow * Window
ImVec2 BackupCursorMaxPos
ImVec2 SizeContents
const char * end() const
Definition: imgui.h:976
float Scale
Definition: imgui.h:1404
ImVector< ImDrawIdx > IdxBuffer
Definition: imgui.h:1218
GLboolean * data
IMGUI_API bool VSliderFloat(const char *label, const ImVec2 &size, float *v, float v_min, float v_max, const char *display_format="%.3f", float power=1.0f, bool render_bg=false)
Definition: imgui.cpp:6633
static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
Definition: imgui.cpp:459
int AutoPosLastDirection
IMGUI_API ImDrawData * GetDrawData()
Definition: imgui.cpp:2025
IMGUI_API void Columns(int count=1, const char *id=NULL, bool border=true)
Definition: imgui.cpp:9398
ImGuiStorage * StateStorage
IMGUI_API void SetWindowFontScale(float scale)
Definition: imgui.cpp:5066
ImVec2 Min
_W64 signed int intptr_t
Definition: stdint.h:118
static void DataTypeApplyOp(ImGuiDataType data_type, int op, void *value1, const void *value2)
Definition: imgui.cpp:6225
char Tooltip[1024]
void InsertChars(int pos, const char *text, const char *text_end=NULL)
Definition: imgui.cpp:7578
IMGUI_API bool DragInt(const char *label, int *v, float v_speed=1.0f, int v_min=0, int v_max=0, const char *display_format="%.0f")
Definition: imgui.cpp:7015
IMGUI_API bool IsMouseDoubleClicked(int button)
Definition: imgui.cpp:3128
ImFontAtlas * Fonts
Definition: imgui.h:799
ImVec2 FontTexUvWhitePixel
static float ImLerp(float a, float b, float t)
GLdouble v
ImGuiWindow * HoveredWindow
IMGUI_API bool IsAnyItemActive()
Definition: imgui.cpp:3233
float ChildWindowRounding
Definition: imgui.h:756
ImVec2 WindowPadding
Definition: imgui.h:752
static void SetWindowPos(ImGuiWindow *window, const ImVec2 &pos, ImGuiSetCond cond)
Definition: imgui.cpp:4799
IMGUI_API void EndMenu()
Definition: imgui.cpp:8937
bool Overlaps(const ImRect &r) const
float BackupCurrentLineHeight
IMGUI_API void ColorConvertHSVtoRGB(float h, float s, float v, float &out_r, float &out_g, float &out_b)
Definition: imgui.cpp:1219
IMGUI_API void PopID()
Definition: imgui.cpp:6123
float WindowRounding
Definition: imgui.h:754
YYCODETYPE lhs
Definition: sqlite3.c:132469
IMGUI_API void PlotLines(const char *label, const float *values, int values_count, int values_offset=0, const char *overlay_text=NULL, float scale_min=FLT_MAX, float scale_max=FLT_MAX, ImVec2 graph_size=ImVec2(0, 0), int stride=sizeof(float))
Definition: imgui.cpp:7211
IMGUI_API void ChannelsSplit(int channels_count)
Definition: imgui_draw.cpp:272
IMGUI_API float GetCursorPosY()
Definition: imgui.cpp:5088
IMGUI_API bool IsItemHovered()
Definition: imgui.cpp:3200
GLdouble y1
IMGUI_API void SetKeyboardFocusHere(int offset=0)
Definition: imgui.cpp:5188
int CaptureMouseNextFrame
ImVec2 GetSize() const
float ScrollbarSize
Definition: imgui.h:764
static float GetDraggedColumnOffset(int column_index)
Definition: imgui.cpp:9328
IMGUI_API void LogText(const char *fmt,...) IM_PRINTFARGS(1)
Definition: imgui.cpp:2709
void * ImTextureID
Definition: imgui.h:68
Definition: parser.hpp:150
IMGUI_API void LogFinish()
Definition: imgui.cpp:5755
IMGUI_API void SetWindowSize(const ImVec2 &size, ImGuiSetCond cond=0)
Definition: imgui.cpp:4864
static void ClearSetNextWindowData()
Definition: imgui.cpp:3419
static ImVec2 * GetStyleVarVec2Addr(ImGuiStyleVar idx)
Definition: imgui.cpp:4636
IMGUI_API int ParseFormatPrecision(const char *fmt, int default_value)
Definition: imgui.cpp:6338
ImGuiWindow * GetCurrentWindowRead()
GLint GLsizei width
IMGUI_API void SetScrollX(float scroll_x)
Definition: imgui.cpp:5155
ImVector< ImGuiPopupRef > CurrentPopupStack
IMGUI_API const Glyph * FindGlyph(ImWchar c) const
IMGUI_API void PopFont()
Definition: imgui.cpp:4549
ImVec2 ScrollTarget
float y
Definition: imgui.h:100
ImVector< float > ItemWidthStack
IMGUI_API void Render()
Definition: imgui.cpp:2619
IMGUI_API void TreeAdvanceToLabelPos()
Definition: imgui.cpp:6078
#define STB_TEXTEDIT_K_LEFT
Definition: imgui.cpp:7529
float x
Definition: imgui.h:90
IMGUI_API bool InputInt(const char *label, int *v, int step=1, int step_fast=100, ImGuiInputTextFlags extra_flags=0)
Definition: imgui.cpp:8296
GLintptr offset
ImVec2 OsImePosRequest
IMGUI_API ImVec4 ColorConvertU32ToFloat4(ImU32 in)
Definition: imgui.cpp:1179
IMGUI_API void PopStyleColor(int count=1)
Definition: imgui.cpp:4609
static void PushMultiItemsWidths(int components, float w_full=0.0f)
Definition: imgui.cpp:4493
ImVector< ImGuiWindow * > ChildWindows
char * PrivateClipboard
char TempBuffer[1024 *3+1]
GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint GLdouble w1
Definition: glext.h:12384
ImVector< ImVec4 > _ClipRectStack
Definition: imgui.h:1226
IMGUI_API void EndMainMenuBar()
Definition: imgui.cpp:8789
float DragCurrentValue
value_type & back()
Definition: imgui.h:925
ImVec2 PreviousValue
IMGUI_API void NewLine()
Definition: imgui.cpp:9269
IMGUI_API void TextColored(const ImVec4 &col, const char *fmt,...) IM_PRINTFARGS(2)
Definition: imgui.cpp:5238
IMGUI_API ImVec2 CalcItemRectClosestPoint(const ImVec2 &pos, bool on_edge=false, float outward=+0.0f)
Definition: imgui.cpp:3273
void Reduce(const ImVec2 &amount)


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:17